Skip to content
Snippets Groups Projects
functionObjectList.C 22.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*---------------------------------------------------------------------------*\
      =========                 |
      \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
       \\    /   O peration     |
    
        \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
    
         \\/     M anipulation  | Copyright (C) 2015-2019 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 "functionObjectList.H"
    #include "Time.H"
    
    #include "mapPolyMesh.H"
    
    #include "profiling.H"
    
    #include "timeControlFunctionObject.H"
    
    #include "dictionaryEntry.H"
    #include "stringOps.H"
    
    #include "Tuple2.H"
    
    
    /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
    
    Foam::fileName Foam::functionObjectList::functionObjectDictPath
    (
        "caseDicts/postProcessing"
    );
    
    
    // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
    
    
    void Foam::functionObjectList::createStateDict() const
    {
        // Cannot set the state dictionary on construction since Time has not
        // been fully initialised
        stateDictPtr_.reset
        (
            new IOdictionary
            (
                IOobject
                (
                    "functionObjectProperties",
                    time_.timeName(),
                    "uniform"/word("functionObjects"),
                    time_,
                    IOobject::READ_IF_PRESENT,
                    IOobject::NO_WRITE
                )
            )
        );
    }
    
    
    
    void Foam::functionObjectList::createOutputRegistry() const
    {
        objectsRegistryPtr_.reset
        (
            new objectRegistry
            (
                IOobject
                (
                    "functionObjectObjects",
                    time_.timeName(),
                    time_,
                    IOobject::NO_READ,
                    IOobject::NO_WRITE
                )
            )
        );
    }
    
    
    
    Foam::autoPtr<Foam::functionObject> Foam::functionObjectList::remove
    
    (
        const word& key,
        label& oldIndex
    )
    
        autoPtr<functionObject> oldptr;
    
        auto iter = indices_.find(key);  // Index of existing functionObject
    
        if (iter.found())
    
            oldIndex = *iter;
    
            // Remove pointer from the old list
            oldptr = this->set(oldIndex, nullptr);
            indices_.erase(iter);
    
        return oldptr;
    
    void Foam::functionObjectList::listDir
    (
        const fileName& dir,
    
    )
    {
        // Search specified directory for functionObject configuration files
    
        for (const fileName& f : fileHandler().readDir(dir))
    
        for (const fileName& d : fileHandler().readDir(dir, fileName::DIRECTORY))
    
        for (const fileName& d : findEtcDirs(functionObjectDictPath))
    
    Foam::fileName Foam::functionObjectList::findDict(const word& funcName)
    {
    
        // First check for functionObject dictionary file in globalCase system/
    
        fileName dictFile = stringOps::expand("<system>")/funcName;
    
        for (const fileName& d : findEtcDirs(functionObjectDictPath))
    
        {
            dictFile = search(funcName, d);
            if (!dictFile.empty())
    
                return dictFile;
    
    bool Foam::functionObjectList::readFunctionObject
    
        const string& funcNameArgs,
    
        HashSet<wordRe>& requiredFields,
    
        // Parse the optional functionObject arguments:
        //     'Q(U)' -> funcName = Q; args = (U); field = U
        //
        // Supports named arguments:
        //     'patchAverage(patch=inlet, p)' -> funcName = patchAverage;
        //         args = (patch=inlet, p); field = p
    
        List<Tuple2<word, string>> namedArgs;
    
        bool hasNamedArg = false;
    
        word::size_type start = 0;
        word::size_type i = 0;
    
        for
        (
            word::const_iterator iter = funcNameArgs.begin();
            iter != funcNameArgs.end();
            ++iter
        )
        {
            char c = *iter;
    
            if (c == '(')
            {
    
                    funcName = funcNameArgs.substr(start, i - start);
    
            else if (c == ',' || c == ')')
    
                    if (hasNamedArg)
    
                    {
                        namedArgs.append
                        (
                            Tuple2<word, string>
                            (
                                argName,
    
                                funcNameArgs.substr(start, i - start)
    
                        hasNamedArg = false;
    
                                word::validate
                                (
                                    funcNameArgs.substr(start, i - start)
                                )
    
                    if (argLevel == 1)
                    {
                        break;
                    }
                    --argLevel;
    
                argName = word::validate
    
                (
                    funcNameArgs.substr(start, i - start)
                );
    
    
                hasNamedArg = true;
    
            }
    
            ++i;
        }
    
        // Search for the functionObject dictionary
    
        fileName path = functionObjectList::findDict(funcName);
    
    
        if (path == fileName::null)
        {
            WarningInFunction
                << "Cannot find functionObject file " << funcName << endl;
    
        }
    
        // Read the functionObject dictionary
    
        autoPtr<ISstream> fileStreamPtr(fileHandler().NewIFstream(path));
        ISstream& fileStream = fileStreamPtr();
    
    
        dictionary funcsDict(fileStream);
    
        dictionary* funcDictPtr = funcsDict.findDict(funcName);
        dictionary& funcDict = (funcDictPtr ? *funcDictPtr : funcsDict);
    
        // Insert the 'field' and/or 'fields' entry corresponding to the optional
    
        // arguments or read the 'field' or 'fields' entry and add the required
    
        if (args.size() == 1)
        {
            funcDict.set("field", args[0]);
    
            funcDict.set("fields", args);
    
        }
        else if (args.size() > 1)
        {
            funcDict.set("fields", args);
    
            requiredFields.insert(funcDict.get<wordRe>("field"));
    
        }
        else if (funcDict.found("fields"))
        {
    
            requiredFields.insert(funcDict.get<wordRes>("fields"));
    
        // Insert named arguments
    
        for (const Tuple2<word, string>& namedArg : namedArgs)
    
        {
            IStringStream entryStream
            (
    
                namedArg.first() + ' ' + namedArg.second() + ';'
    
            funcDict.set(entry::New(entryStream).ptr());
        }
    
    
        // Insert the region name if specified
        if (region != word::null)
        {
            funcDict.set("region", region);
        }
    
    
        // Merge this functionObject dictionary into functionsDict
        dictionary funcArgsDict;
    
        funcArgsDict.add(word::validate(funcNameArgs), funcDict);
    
        functionsDict.merge(funcArgsDict);
    
        return true;
    
    // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
    
    Foam::functionObjectList::functionObjectList
    (
    
        const Time& runTime,
    
        PtrList<functionObject>(),
        digests_(),
    
        time_(runTime),
        parentDict_(runTime.controlDict()),
    
        execution_(execution),
        updated_(false)
    
    {}
    
    
    Foam::functionObjectList::functionObjectList
    (
    
        const Time& runTime,
    
        const dictionary& parentDict,
    
        PtrList<functionObject>(),
        digests_(),
    
        parentDict_(parentDict),
    
        execution_(execution),
        updated_(false)
    
    Foam::autoPtr<Foam::functionObjectList> Foam::functionObjectList::New
    (
        const argList& args,
        const Time& runTime,
    
        HashSet<wordRe>& requiredFields
    
        // Merge any functions from the provided controlDict
    
            dictionaryEntry("functions", controlDict, dictionary::null),
            true
    
        dictionary& functionsDict = controlDict.subDict("functions");
    
    
        const word regionName = args.opt<word>("region", "");
    
        bool modifiedControlDict = false;
    
            modifiedControlDict = true;
    
            controlDict.merge
            (
                IOdictionary
    
                        args["dict"],
                        runTime,
                        IOobject::MUST_READ_IF_MODIFIED
    
        {
            modifiedControlDict = true;
    
            readFunctionObject
            (
                args["func"],
                functionsDict,
                requiredFields,
    
        {
            modifiedControlDict = true;
    
            wordList funcNames = args.getList<word>("funcs");
    
    
            for (const word& funcName : funcNames)
    
        autoPtr<functionObjectList> functionsPtr;
    
        if (modifiedControlDict)
        {
    
            functionsPtr.reset(new functionObjectList(runTime, controlDict));
    
            functionsPtr.reset(new functionObjectList(runTime));
    
        functionsPtr->start();
    
        return functionsPtr;
    
    // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
    
    
    Foam::label Foam::functionObjectList::triggerIndex() const
    {
        label triggeri = labelMin;
        stateDict().readIfPresent("triggerIndex", triggeri);
    
        return triggeri;
    }
    
    
    
    void Foam::functionObjectList::resetState()
    {
        // Reset (re-read) the state dictionary
        stateDictPtr_.clear();
        createStateDict();
    }
    
    
    
    Foam::IOdictionary& Foam::functionObjectList::stateDict()
    {
        if (!stateDictPtr_.valid())
        {
            createStateDict();
        }
    
    
        return *stateDictPtr_;
    
    }
    
    
    const Foam::IOdictionary& Foam::functionObjectList::stateDict() const
    {
        if (!stateDictPtr_.valid())
        {
            createStateDict();
        }
    
    
        return *stateDictPtr_;
    
    Foam::objectRegistry& Foam::functionObjectList::storedObjects()
    {
        if (!objectsRegistryPtr_.valid())
        {
            createOutputRegistry();
        }
    
        return *objectsRegistryPtr_;
    }
    
    
    const Foam::objectRegistry& Foam::functionObjectList::storedObjects() const
    {
        if (!objectsRegistryPtr_.valid())
        {
            createOutputRegistry();
        }
    
        return *objectsRegistryPtr_;
    }
    
    
    
    void Foam::functionObjectList::clear()
    {
        PtrList<functionObject>::clear();
        digests_.clear();
        indices_.clear();
        updated_ = false;
    }
    
    
    
    Foam::label Foam::functionObjectList::findObjectID(const word& name) const
    {
    
        label id = 0;
    
        for (const functionObject& funcObj : functions())
    
            if (funcObj.name() == name)
    
    void Foam::functionObjectList::on()
    {
        execution_ = true;
    }
    
    
    void Foam::functionObjectList::off()
    {
    
        // For safety, also force a read() when execution is resumed
    
        updated_ = execution_ = false;
    }
    
    
    bool Foam::functionObjectList::status() const
    {
        return execution_;
    }
    
    
    
    bool Foam::functionObjectList::start()
    {
    
        return read();
    
    bool Foam::functionObjectList::execute()
    
            if (!updated_)
    
            for (functionObject& funcObj : functions())
    
                const word& objName = funcObj.name();
    
                {
                    addProfiling(fo, "functionObject::" + objName + "::execute");
    
                    ok = funcObj.execute() && ok;
    
                {
                    addProfiling(fo, "functionObject::" + objName + "::write");
    
                    ok = funcObj.write() && ok;
    
        // Force writing of state dictionary after function object execution
    
        if (time_.writeTime())
    
        {
            label oldPrecision = IOstream::precision_;
            IOstream::precision_ = 16;
    
            stateDictPtr_->writeObject
            (
                IOstream::ASCII,
                IOstream::currentVersion,
    
            );
    
            IOstream::precision_ = oldPrecision;
        }
    
    
    bool Foam::functionObjectList::execute(const label subIndex)
    {
        bool ok = execution_;
    
        if (ok)
        {
    
            for (functionObject& funcObj : functions())
    
            {
                ok = funcObj.execute(subIndex) && ok;
            }
        }
    
        return ok;
    }
    
    
    bool Foam::functionObjectList::execute
    (
    
        const label subIndex
    )
    {
        bool ok = execution_;
    
        if (ok && functionNames.size())
        {
    
            for (functionObject& funcObj : functions())
    
                if (stringOps::match(functionNames, funcObj.name()))
    
                {
                    ok = funcObj.execute(subIndex) && ok;
                }
            }
        }
    
        return ok;
    }
    
    
    
    bool Foam::functionObjectList::end()
    {
        bool ok = true;
    
        if (execution_)
        {
            if (!updated_)
            {
                read();
            }
    
    
            for (functionObject& funcObj : functions())
    
                const word& objName = funcObj.name();
    
    
                addProfiling(fo, "functionObject::" + objName + "::end");
    
                ok = funcObj.end() && ok;
    
    bool Foam::functionObjectList::adjustTimeStep()
    {
        bool ok = true;
    
        if (execution_)
        {
            if (!updated_)
            {
                read();
            }
    
    
            for (functionObject& funcObj : functions())
    
                const word& objName = funcObj.name();
    
    
                addProfiling(fo, "functionObject::" + objName + "::adjustTimeStep");
    
                ok = funcObj.adjustTimeStep() && ok;
    
    bool Foam::functionObjectList::read()
    {
    
        if (!stateDictPtr_.valid())
        {
            createStateDict();
        }
    
    
        updated_ = execution_;
    
    
        if (!execution_)
        {
    
        // Update existing and add new functionObjects
    
        const entry* entryPtr =
            parentDict_.findEntry("functions", keyType::LITERAL);
    
        bool ok = true;
    
        if (!entryPtr)
        {
            // No functions
            PtrList<functionObject>::clear();
            digests_.clear();
            indices_.clear();
        }
        else if (!entryPtr->isDict())
        {
            // Bad entry type
            ok = false;
            FatalIOErrorInFunction(parentDict_)
                << "'functions' entry is not a dictionary"
                << exit(FatalIOError);
        }
        else
        {
            const dictionary& functionsDict = entryPtr->dict();
    
            PtrList<functionObject> newPtrs(functionsDict.size());
            List<SHA1Digest> newDigs(functionsDict.size());
            HashTable<label> newIndices;
    
            addProfiling(fo, "functionObjects::read");
    
            const_cast<Time&>(time_).libs().open
            (
                functionsDict,
                "libs",
                functionObject::dictionaryConstructorTablePtr_
            );
    
    
            label nFunc = 0;
    
            for (const entry& dEntry : functionsDict)
    
                const word& key = dEntry.keyword();
    
                        IOWarningInFunction(parentDict_)
                            << "Entry " << key << " is not a dictionary" << endl;
    
                const dictionary& dict = dEntry.dict();
    
    
                bool enabled = dict.lookupOrDefault("enabled", true);
    
                label oldIndex = -1;
                autoPtr<functionObject> objPtr = remove(key, oldIndex);
    
                    // Re-read if dictionary content changed for
                    // existing functionObject
                    if (enabled && newDigs[nFunc] != digests_[oldIndex])
    
                        addProfiling
                        (
                            fo2,
                            "functionObject::" + objPtr->name() + "::read"
                        );
    
                        if (functionObjects::timeControl::entriesPresent(dict))
                        {
                            if (isA<functionObjects::timeControl>(objPtr()))
                            {
                                // Already a time control - normal read
                                enabled = objPtr->read(dict);
                            }
                            else
                            {
                                // Was not a time control - need to re-create
                                objPtr.reset
                                (
                                    new functionObjects::timeControl
                                    (
                                        key,
                                        time_,
                                        dict
                                    )
                                );
    
                                enabled = true;
                            }
                        }
                        else
                        {
                            // Plain function object - normal read
                            enabled = objPtr->read(dict);
                        }
    
    
                        ok = enabled && ok;
    
                        // Delete disabled or an invalid(read) functionObject
                        objPtr.clear();
    
                    // Throw FatalError, FatalIOError as exceptions
                    const bool throwingError = FatalError.throwExceptions();
                    const bool throwingIOerr = FatalIOError.throwExceptions();
    
    
                            "functionObject::" + key + "::new"
    
                        if (functionObjects::timeControl::entriesPresent(dict))
    
                            (
                                new functionObjects::timeControl(key, time_, dict)
                            );
                        }
                        else
                        {
                            foPtr = functionObject::New(key, time_, dict);
                        }
    
                    catch (const Foam::IOerror& ioErr)
    
                    catch (const Foam::error& err)
    
                        // Bit of trickery to get the original message
                        err.write(Warning, false);
    
                        InfoInFunction
                            << nl
    
                            << "--> while loading function object '" << key << "'"
                            << nl << endl;
    
    
                    // Restore previous exception throwing state
                    FatalError.throwExceptions(throwingError);
                    FatalIOError.throwExceptions(throwingIOerr);
    
                    // Required functionObject to be valid on all processors
    
                    if (returnReduce(foPtr.valid(), andOp<bool>()))
    
                        objPtr.reset(foPtr.release());
    
                // Insert active functionObject into the list
    
                    newPtrs.set(nFunc, objPtr);
                    newIndices.insert(key, nFunc);
    
            newPtrs.resize(nFunc);
            newDigs.resize(nFunc);
    
            // Updating PtrList of functionObjects deletes any
    
            PtrList<functionObject>::transfer(newPtrs);
    
            digests_.transfer(newDigs);
    
            indices_.transfer(newIndices);
    
    bool Foam::functionObjectList::filesModified() const
    {
        bool ok = false;
        if (execution_)
        {
    
            for (const functionObject& funcObj : functions())
    
                bool changed = funcObj.filesModified();
    
    void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
    {
        if (execution_)
        {
    
            for (functionObject& funcObj : functions())
    
                funcObj.updateMesh(mpm);
    
            }
        }
    }
    
    
    void Foam::functionObjectList::movePoints(const polyMesh& mesh)
    {
        if (execution_)
        {
    
            for (functionObject& funcObj : functions())
    
                funcObj.movePoints(mesh);
    
    // ************************************************************************* //