diff --git a/applications/test/objectRegistry2/Make/files b/applications/test/objectRegistry2/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..208771853c25a1483c3222f71cd5639587c9247f --- /dev/null +++ b/applications/test/objectRegistry2/Make/files @@ -0,0 +1,3 @@ +Test-objectRegistry2.C + +EXE = $(FOAM_USER_APPBIN)/Test-objectRegistry2 diff --git a/applications/test/objectRegistry2/Make/options b/applications/test/objectRegistry2/Make/options new file mode 100644 index 0000000000000000000000000000000000000000..969020c4afaf5d784299462b9e1af282040ba6b4 --- /dev/null +++ b/applications/test/objectRegistry2/Make/options @@ -0,0 +1,8 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude + +EXE_LIBS = \ + -lfiniteVolume \ + -lmeshTools \ + -lgenericPatchFields diff --git a/applications/test/objectRegistry2/Test-objectRegistry2.C b/applications/test/objectRegistry2/Test-objectRegistry2.C new file mode 100644 index 0000000000000000000000000000000000000000..eab159ccfc28deecff5009d2e046047fc0ed49b7 --- /dev/null +++ b/applications/test/objectRegistry2/Test-objectRegistry2.C @@ -0,0 +1,307 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +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/>. + +Application + Test-objectRegistry2 + +Description + Print objectRegistry information, with some additional tests. + +\*---------------------------------------------------------------------------*/ + +#include "argList.H" +#include "Time.H" +#include "fvCFD.H" +#include "fvMesh.H" +#include "volFields.H" +#include "IOobjectList.H" +#include "timeSelector.H" +#include "ReadFields.H" +#include "IOstreams.H" + +using namespace Foam; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class Type> +bool loadField(fvMesh& mesh, const word& fieldName) +{ + typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType; + typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType; + + if (mesh.objectRegistry::found(fieldName)) + { + // Info<< fieldName << " already in database" << endl; + return false; + } + + IOobject fieldHeader + ( + fieldName, + mesh.time().timeName(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ); + + if (fieldHeader.typeHeaderOk<VolFieldType>(true, true, false)) + { + // Store field on mesh database + VolFieldType* ptr = new VolFieldType(fieldHeader, mesh); + mesh.objectRegistry::store(ptr); + return true; + } + else if (fieldHeader.typeHeaderOk<SurfaceFieldType>(true, true, false)) + { + // Store field on mesh database + SurfaceFieldType* ptr = new SurfaceFieldType(fieldHeader, mesh); + mesh.objectRegistry::store(ptr); + return true; + } + + return false; +} + + +bool loadField(fvMesh& mesh, const word& fieldName) +{ + return + ( + !mesh.objectRegistry::found(fieldName) + && + ( + loadField<scalar>(mesh, fieldName) + || loadField<vector>(mesh, fieldName) + || loadField<sphericalTensor>(mesh, fieldName) + || loadField<symmTensor>(mesh, fieldName) + || loadField<tensor>(mesh, fieldName) + ) + ); +} + + +void loadFields(fvMesh& mesh, const IOobjectList& objects) +{ + for (const word& fieldName : objects.names()) + { + loadField(mesh, fieldName); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void printRegistry +( + Foam::Ostream& os, + const Foam::objectRegistry& obr, + Foam::label indent = 4 +); + + +void printRegistry +( + Foam::Ostream& os, + const Foam::objectRegistry& obr, + Foam::label indent +) +{ + wordList names(obr.sortedNames()); + wordList regs(obr.sortedNames<objectRegistry>()); + + std::string prefix; + for (label i=indent; i; --i) + { + prefix += ' '; + } + + os << '#' << prefix.c_str() << obr.name() + << " parent:" << obr.parent().name() << nl; + + os << ' ' << prefix.c_str() << "objects: " << flatOutput(names) << nl; + os << ' ' << prefix.c_str() << "registries: " << flatOutput(regs) << nl; + + + // Print, but skip expansion of sub-registries for now + for (const word& name : names) + { + os << (regs.found(name) ? '-' : ' ') + << prefix.c_str() << name << " => " << obr[name]->type() << nl; + } + for (label i=indent; i; --i) + { + os << '-'; // divider + } + os << '\n'; + + // Now descend into the sub-registries + for (const word& name : regs) + { + const objectRegistry& next = obr.lookupObject<objectRegistry> + ( + name, + false // non-recursive + ); + + os << prefix.c_str() + << "current:" << obr.name() << " next:" + << next.name() << " next-parent:" << next.parent().name() << nl; + + os << prefix.c_str() << name << " => " << obr[name]->type(); + + if ("dictionary" == obr[name]->type()) + { + os << " (skip dictionary)" << nl; + } + else + { + os << nl; + printRegistry(os, next, indent + 4); + } + } +} + + +template<class Type> +void filterTest(const objectRegistry& obr, const wordRe& re) +{ + Info<< nl << "Filter on names:" << nl; + + Info<< "Filter = " << re << nl; + + const word& typeName = Type::typeName; + + Info<< " <" << typeName <<">(" << re << ") : " + << obr.count<Type>(re) << nl + << " (" << typeName << "::typeName, " << re << ") : " + << obr.count(typeName, re) << nl; + + Info<< " <" << typeName << ">(" << re << ") : " + << flatOutput(obr.sortedNames<Type>(re)) << nl + // << flatOutput(obr.names<Type>(re)) << nl + << " (" << typeName << "::typeName, " << re << ") : " + << flatOutput(obr.sortedNames(typeName, re)) << nl + //<< flatOutput(obr.names(typeName, re)) << nl + ; + + + wordRe reClass("vol.*Field", wordRe::REGEX); + wordRe re2(re, wordRe::REGEX_ICASE); + + Info<< "General" << nl + << " <void>(" << re << ") : " + << flatOutput(obr.sortedNames<void>(re)) << nl + << " (" << reClass << ", " << re2 <<" ignore-case) : " + << flatOutput(obr.sortedNames(reClass, re2)) << nl + ; + + Info<< nl; +} + + +void registryTests(const objectRegistry& obr) +{ + Info<< nl << "Registry: " << obr.name() << nl + << " names: " << flatOutput(obr.sortedNames()) << nl; + + Info<< "count" << nl + << " <void>() : " << obr.count<void>() << nl + << " <labelList>() : " << obr.count<labelList>() << nl + << " <labelList>(strict) : " << obr.count<labelList>(true) << nl + << " <scalarList>() : " << obr.count<scalarList>() << nl + << " <scalarList>(strict) : " << obr.count<scalarList>(true) << nl; + Info<< " <volScalarField>() : " + << obr.count<volScalarField>() << nl + << " (volScalarField::typeName) : " + << obr.count(volScalarField::typeName) << nl; + Info<< " <volVectorField>() : " + << obr.count<volVectorField>() << nl + << " (volVectorField::typeName) : " + << obr.count(volVectorField::typeName) << nl; + + Info<< nl << "Filter on names:" << nl; + + filterTest<volScalarField>(obr, wordRe("[p-z].*", wordRe::DETECT)); + + Info<< nl; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Main program: + +int main(int argc, char *argv[]) +{ + argList::noBanner(); + argList::noParallel(); +// argList::addOption +// ( +// "filter", +// "wordRes", +// "filter keys with names or regexs" +// ); + + // timeSelector::addOptions(); + timeSelector::addOptions(true, true); + + #include "setRootCase.H" + +// wordRes matcher; +// if (args.readListIfPresent<wordRe>("filter", matcher)) +// { +// Info<<"limit names: " << matcher << nl; +// } + + #include "createTime.H" + #include "createMesh.H" + + instantList timeDirs = timeSelector::select0(runTime, args); + + forAll(timeDirs, timeI) + { + runTime.setTime(timeDirs[timeI], timeI); + + Info<< "Time: " << runTime.timeName() << endl; + + // Read objects in time directory + IOobjectList objects(mesh, runTime.timeName()); + + // Read volFields + loadFields(mesh, objects); + + printRegistry(Info, mesh); + + registryTests(mesh); + + Info<< nl; + } + + + Info<<"\nEnd\n" << endl; + + return 0; +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.C b/src/OpenFOAM/db/objectRegistry/objectRegistry.C index d2b0a1a2c68be61a7c5636ec0243b8cb44f24115..a747de2c83a49580e23445227fbf380ea3387e8f 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistry.C +++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.C @@ -111,6 +111,13 @@ Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classes() const } +Foam::label Foam::objectRegistry::count(const char* clsName) const +{ + // No nullptr check - only called with string literals + return count(static_cast<word>(clsName)); +} + + Foam::wordList Foam::objectRegistry::names() const { return HashTable<regIOobject*>::toc(); diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.H b/src/OpenFOAM/db/objectRegistry/objectRegistry.H index 30c03f8e31b4b05f25aa0e0a7c70710a2af010c1..d05f5edf0a4cc15430bc44c3cab8f1948acfc387 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistry.H +++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.H @@ -81,6 +81,25 @@ class objectRegistry // Used to terminate searching within the ancestors bool parentNotTime() const; + //- Templated implementation for count() + // The number of items with a matching class + template<class MatchPredicate1, class MatchPredicate2> + static label countImpl + ( + const objectRegistry& list, + const MatchPredicate1& matchClass, + const MatchPredicate2& matchName + ); + + //- Templated implementation for count() + // The number of items with a matching class + template<class Type, class MatchPredicate> + static label countTypeImpl + ( + const objectRegistry& list, + const MatchPredicate& matchName + ); + //- Templated implementation for classes() template<class MatchPredicate> static HashTable<wordHashSet> classesImpl @@ -173,6 +192,45 @@ public: HashTable<wordHashSet> classes(const MatchPredicate& matchName) const; + // Number of items + + //- The number of objects of the given class name + // \note uses the class type() method + label count(const char* clsName) const; + + //- The number of objects of the given class name + // \note uses the class type() method + template<class MatchPredicate> + label count(const MatchPredicate& matchClass) const; + + //- The number of objects of the given class name + // \note uses the class type() method + template<class MatchPredicate1, class MatchPredicate2> + label count + ( + const MatchPredicate1& matchClass, + const MatchPredicate2& matchName + ) const; + + //- The names of objects with a class satisfying \c isA\<Type\> + // + // \param strict use \c isType\<Type\> instead of \c isA\<Type\> + // + // \note The values of \c count\<Type\>() and \c count(Type::typeName) + // may be inconsistent, since they use different mechanisms for + // testing the class type. + // \note If \a Type is \c void, no isA check is used (always true). + template<class Type> + label count(const bool strict = false) const; + + //- The names of objects with a class satisfying \c isA\<Type\> + //- that also have a matching object name. + // + // \note If \a Type is \c void, no isA check is used (always true). + template<class Type, class MatchPredicate> + label count(const MatchPredicate& matchName) const; + + // Summary of names //- The names of all objects diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C index c63ff76acec7223260566cb99a2130b1d42d2040..e75a304edae4462e03284506fe9de255f4eb001c 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C +++ b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C @@ -55,6 +55,59 @@ Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classesImpl } +// Templated implementation for count() +template<class MatchPredicate1, class MatchPredicate2> +Foam::label Foam::objectRegistry::countImpl +( + const objectRegistry& list, + const MatchPredicate1& matchClass, + const MatchPredicate2& matchName +) +{ + label count = 0; + + forAllConstIters(list, iter) + { + const regIOobject* obj = iter.object(); + + if (matchClass(obj->type()) && matchName(obj->name())) + { + ++count; + } + } + + return count; +} + + +// Templated implementation for count() +template<class Type, class MatchPredicate> +Foam::label Foam::objectRegistry::countTypeImpl +( + const objectRegistry& list, + const MatchPredicate& matchName +) +{ + label count = 0; + + forAllConstIters(list, iter) + { + const regIOobject* obj = iter.object(); + + if + ( + (std::is_void<Type>::value || isA<Type>(*obj)) + && matchName(obj->name()) + ) + { + ++count; + } + } + + return count; +} + + // Templated implementation for names(), sortedNames() template<class MatchPredicate1, class MatchPredicate2> Foam::wordList Foam::objectRegistry::namesImpl @@ -141,6 +194,63 @@ Foam::objectRegistry::classes } +template<class MatchPredicate> +Foam::label Foam::objectRegistry::count +( + const MatchPredicate& matchClass +) const +{ + return countImpl(*this, matchClass, predicates::always()); +} + + +template<class MatchPredicate1, class MatchPredicate2> +Foam::label Foam::objectRegistry::count +( + const MatchPredicate1& matchClass, + const MatchPredicate2& matchName +) const +{ + return countImpl(*this, matchClass, matchName); +} + + +template<class Type, class MatchPredicate> +Foam::label Foam::objectRegistry::count +( + const MatchPredicate& matchName +) const +{ + return countTypeImpl<Type>(*this, matchName); +} + + +template<class Type> +Foam::label Foam::objectRegistry::count +( + const bool strict +) const +{ + label nObjects = 0; + + forAllConstIters(*this, iter) + { + const regIOobject* obj = iter.object(); + + if + ( + std::is_void<Type>::value + || (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj))) + ) + { + ++nObjects; + } + } + + return nObjects; +} + + template<class MatchPredicate> Foam::wordList Foam::objectRegistry::names ( @@ -227,13 +337,11 @@ Foam::HashTable<const Type*> Foam::objectRegistry::lookupClass forAllConstIters(*this, iter) { - if (strict ? isType<Type>(*iter()) : bool(isA<Type>(*iter()))) + const regIOobject* obj = iter.object(); + + if (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj))) { - objectsOfClass.insert - ( - iter()->name(), - dynamic_cast<const Type*>(iter()) - ); + objectsOfClass.insert(obj->name(), dynamic_cast<const Type*>(obj)); } } @@ -251,13 +359,11 @@ Foam::HashTable<Type*> Foam::objectRegistry::lookupClass forAllIters(*this, iter) { - if (strict ? isType<Type>(*iter()) : bool(isA<Type>(*iter()))) + regIOobject* obj = iter.object(); + + if (strict ? isType<Type>(*obj) : bool(isA<Type>(*obj))) { - objectsOfClass.insert - ( - iter()->name(), - dynamic_cast<Type*>(iter()) - ); + objectsOfClass.insert(obj->name(), dynamic_cast<Type*>(obj)); } }