Skip to content
Snippets Groups Projects
functionObjectList.C 20.1 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-2017 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
                )
            )
        );
    }
    
    
    
    Foam::functionObject* Foam::functionObjectList::remove
    (
        const word& key,
        label& oldIndex
    )
    
        functionObject* ptr = nullptr;
    
    
        // Find index of existing functionObject
        HashTable<label>::iterator fnd = indices_.find(key);
    
        if (fnd != indices_.end())
        {
    
            oldIndex = fnd();
    
    
            // Retrieve the pointer and remove it from the old list
    
            ptr = this->set(oldIndex, 0).ptr();
    
            indices_.erase(fnd);
        }
    
    void Foam::functionObjectList::listDir
    (
        const fileName& dir,
        HashSet<word>& foMap
    )
    {
        // Search specified directory for functionObject configuration files
        {
    
            fileNameList foFiles(fileHandler().readDir(dir));
    
            forAll(foFiles, f)
            {
                if (foFiles[f].ext().empty())
                {
                    foMap.insert(foFiles[f]);
                }
            }
        }
    
        // Recurse into sub-directories
        {
    
            fileNameList foDirs(fileHandler().readDir(dir, fileName::DIRECTORY));
    
    void Foam::functionObjectList::list()
    {
        HashSet<word> foMap;
    
        fileNameList etcDirs(findEtcDirs(functionObjectDictPath));
    
        forAll(etcDirs, ed)
        {
    
        }
    
        Info<< nl
            << "Available configured functionObjects:"
            << foMap.sortedToc()
            << nl;
    }
    
    
    
    Foam::fileName Foam::functionObjectList::findDict(const word& funcName)
    {
        // First check if there is a functionObject dictionary file in the
        // case system directory
        fileName dictFile = stringOps::expand("$FOAM_CASE")/"system"/funcName;
    
        if (isFile(dictFile))
        {
            return dictFile;
        }
        else
        {
            fileNameList etcDirs(findEtcDirs(functionObjectDictPath));
    
            forAll(etcDirs, i)
            {
                dictFile = search(funcName, etcDirs[i]);
                if (!dictFile.empty())
                {
                    return dictFile;
                }
            }
        }
    
        return fileName::null;
    }
    
    
    
    bool Foam::functionObjectList::readFunctionObject
    
        const string& funcNameArgs,
    
        HashSet<word>& requiredFields,
        const word& region
    
        // 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 namedArg = false;
        word argName;
    
    
        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 (namedArg)
                    {
                        namedArgs.append
                        (
                            Tuple2<word, string>
                            (
                                argName,
    
                                funcNameArgs.substr(start, i - start)
    
                            (
                                funcNameArgs.substr(start, i - start)
                            )
    
                    if (argLevel == 1)
                    {
                        break;
                    }
                    --argLevel;
    
                argName = word::validate
    
                (
                    funcNameArgs.substr(start, i - start)
                );
    
    
                start = i+1;
                namedArg = true;
    
            }
    
            ++i;
        }
    
        // Search for the functionObject dictionary
        fileName path = findDict(funcName);
    
        if (path == fileName::null)
        {
            WarningInFunction
                << "Cannot find functionObject file " << funcName << endl;
    
        }
    
        // Read the functionObject dictionary
    
        //IFstream fileStream(path);
        autoPtr<ISstream> fileStreamPtr(fileHandler().NewIFstream(path));
        ISstream& fileStream = fileStreamPtr();
    
    
        dictionary funcsDict(fileStream);
    
        dictionary* funcDictPtr = &funcsDict;
    
        if (funcsDict.found(funcName) && funcsDict.isDict(funcName))
        {
            funcDictPtr = &funcsDict.subDict(funcName);
        }
    
        dictionary& funcDict = *funcDictPtr;
    
        // 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(word(funcDict.lookup("field")));
    
        }
        else if (funcDict.found("fields"))
        {
    
            requiredFields.insert(wordList(funcDict.lookup("fields")));
    
        // Insert named arguments
        forAll(namedArgs, i)
        {
            IStringStream entryStream
            (
                namedArgs[i].first() + ' ' + namedArgs[i].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,
    
        dictionary& controlDict,
        HashSet<word>& requiredFields
    
        autoPtr<functionObjectList> functionsPtr;
    
    
            dictionaryEntry("functions", controlDict, dictionary::null)
    
        dictionary& functionsDict = controlDict.subDict("functions");
    
    
        word region = word::null;
    
        // Set the region name if specified
        if (args.optionFound("region"))
        {
            region = args["region"];
        }
    
    
        if
        (
            args.optionFound("dict")
         || args.optionFound("func")
         || args.optionFound("funcs")
        )
    
                    IOdictionary
                    (
                        IOobject
                        (
                            args["dict"],
                            runTime,
                            IOobject::MUST_READ_IF_MODIFIED
                        )
                    )
                );
            }
    
            if (args.optionFound("func"))
            {
    
                readFunctionObject
                (
                    args["func"],
                    functionsDict,
                    requiredFields,
                    region
                );
    
            }
    
            if (args.optionFound("funcs"))
            {
                wordList funcs(args.optionLookup("funcs")());
    
                forAll(funcs, i)
                {
    
                    readFunctionObject
                    (
                        funcs[i],
                        functionsDict,
                        requiredFields,
                        region
                    );
    
            functionsPtr.reset(new functionObjectList(runTime, controlDict));
    
            functionsPtr.reset(new functionObjectList(runTime));
    
        functionsPtr->start();
    
        return functionsPtr;
    
    // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
    
    Foam::functionObjectList::~functionObjectList()
    {}
    
    
    // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
    
    
    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_();
    }
    
    
    
    void Foam::functionObjectList::clear()
    {
        PtrList<functionObject>::clear();
        digests_.clear();
        indices_.clear();
        updated_ = false;
    }
    
    
    
    Foam::label Foam::functionObjectList::findObjectID(const word& name) const
    {
        forAll(*this, objectI)
        {
            if (operator[](objectI).name() == name)
            {
                return objectI;
            }
        }
    
        return -1;
    }
    
    
    
    void Foam::functionObjectList::on()
    {
        execution_ = true;
    }
    
    
    void Foam::functionObjectList::off()
    {
    
        // For safety, also force a read() when execution is turned back on
    
        updated_ = execution_ = false;
    }
    
    
    bool Foam::functionObjectList::status() const
    {
        return execution_;
    }
    
    
    
    bool Foam::functionObjectList::start()
    {
    
        return read();
    
    bool Foam::functionObjectList::execute()
    
            if (!updated_)
    
            forAll(*this, objectI)
    
                const word& objName = operator[](objectI).name();
                {
                    addProfiling(fo, "functionObject::" + objName + "::execute");
    
                    ok = operator[](objectI).execute() && ok;
                }
    
                {
                    addProfiling(fo, "functionObject::" + objName + "::write");
    
                    ok = operator[](objectI).write() && ok;
                }
    
        // Force writing of state dictionary after function object execution
        if (time_.outputTime())
        {
            label oldPrecision = IOstream::precision_;
            IOstream::precision_ = 16;
    
            stateDictPtr_->writeObject
            (
                IOstream::ASCII,
                IOstream::currentVersion,
    
            );
    
            IOstream::precision_ = oldPrecision;
        }
    
    
    bool Foam::functionObjectList::end()
    {
        bool ok = true;
    
        if (execution_)
        {
            if (!updated_)
            {
                read();
            }
    
    
            forAll(*this, objectI)
    
                const word& objName = operator[](objectI).name();
    
                addProfiling(fo, "functionObject::" + objName + "::end");
    
                ok = operator[](objectI).end() && ok;
    
    bool Foam::functionObjectList::adjustTimeStep()
    {
        bool ok = true;
    
        if (execution_)
        {
            if (!updated_)
            {
                read();
            }
    
            forAll(*this, objectI)
            {
    
                const word& objName = operator[](objectI).name();
    
                addProfiling(fo, "functionObject::" + objName + "::adjustTimeStep");
    
    bool Foam::functionObjectList::read()
    {
    
        if (!stateDictPtr_.valid())
        {
            createStateDict();
        }
    
    
        bool ok = true;
        updated_ = execution_;
    
    
        if (!execution_)
        {
    
        // Update existing and add new functionObjects
    
        const entry* entryPtr = parentDict_.lookupEntryPtr
        (
            "functions",
            false,
            false
        );
    
    
        if (entryPtr)
    
            PtrList<functionObject> newPtrs;
    
            List<SHA1Digest> newDigs;
    
            HashTable<label> newIndices;
    
            label nFunc = 0;
    
            addProfiling(fo,"functionObjects::read");
    
    
                FatalIOErrorInFunction(parentDict_)
                    << "'functions' entry is not a dictionary"
                    << exit(FatalIOError);
            }
    
    
            const dictionary& functionsDict = entryPtr->dict();
    
            const_cast<Time&>(time_).libs().open
            (
                functionsDict,
                "libs",
                functionObject::dictionaryConstructorTablePtr_
            );
    
            newPtrs.setSize(functionsDict.size());
            newDigs.setSize(functionsDict.size());
    
            forAllConstIter(dictionary, functionsDict, iter)
    
                        IOWarningInFunction(parentDict_)
                            << "Entry " << key << " is not a dictionary" << endl;
    
                    continue;
                }
    
                const dictionary& dict = iter().dict();
                bool enabled = dict.lookupOrDefault("enabled", true);
    
                label oldIndex;
                functionObject* objPtr = remove(key, oldIndex);
    
                if (objPtr)
                {
                    if (enabled)
    
                        // Dictionary changed for an existing functionObject
    
                        if (newDigs[nFunc] != digests_[oldIndex])
                        {
    
                            addProfiling
                            (
                                fo2,
                                "functionObject::" + objPtr->name() + "::read"
                            );
    
    
                            enabled = objPtr->read(dict);
                            ok = enabled && ok;
    
                        // Delete the disabled/invalid(read) functionObject
    
                    // Throw FatalError, FatalIOError as exceptions
                    const bool throwingError = FatalError.throwExceptions();
                    const bool throwingIOerr = FatalIOError.throwExceptions();
    
    
                            "functionObject::" + key + "::new"
    
                        if (functionObjects::timeControl::entriesPresent(dict))
    
                        {
                            foPtr.set
                            (
                                new functionObjects::timeControl(key, time_, dict)
                            );
                        }
                        else
                        {
                            foPtr = functionObject::New(key, time_, dict);
                        }
    
                    catch (Foam::error& err)
                    {
                        WarningInFunction
                            << "Caught FatalError " << err << nl << endl;
                    }
    
    
                    // Restore previous exception throwing state
                    FatalError.throwExceptions(throwingError);
                    FatalIOError.throwExceptions(throwingIOerr);
    
                    // If one processor only has thrown an exception (so exited the
                    // constructor) invalidate the whole functionObject
                    if (returnReduce(foPtr.valid(), andOp<bool>()))
    
                // Insert active functionObjects into the list
                if (objPtr)
                {
    
                    newPtrs.set(nFunc, objPtr);
                    newIndices.insert(key, nFunc);
                    nFunc++;
    
    
            newPtrs.setSize(nFunc);
    
            newDigs.setSize(nFunc);
    
            // Updating the PtrList of functionObjects deletes any
            // existing unused functionObjects
    
            PtrList<functionObject>::transfer(newPtrs);
    
            digests_.transfer(newDigs);
    
            indices_.transfer(newIndices);
    
            PtrList<functionObject>::clear();
    
            digests_.clear();
    
            indices_.clear();
    
    bool Foam::functionObjectList::filesModified() const
    {
        bool ok = false;
        if (execution_)
        {
            forAll(*this, objectI)
            {
                bool changed = operator[](objectI).filesModified();
                ok = ok || changed;
            }
        }
        return ok;
    }
    
    
    
    void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
    {
        if (execution_)
        {
            forAll(*this, objectI)
            {
                operator[](objectI).updateMesh(mpm);
            }
        }
    }
    
    
    void Foam::functionObjectList::movePoints(const polyMesh& mesh)
    {
        if (execution_)
        {
            forAll(*this, objectI)
            {
                operator[](objectI).movePoints(mesh);
            }
        }
    }
    
    
    
    // ************************************************************************* //