View Issue Details

IDProjectCategoryView StatusLast Update
0004183OpenFOAMContributionpublic2024-11-26 12:00
Reporternguyenhung97 Assigned Towill  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionno change required 
PlatformUbuntuOSOtherOS Version(please specify)
Product Version12 
Summary0004183: make the write operation of particle interaction as an option for log-friendly purpose for lots of patches
DescriptionNormally, particle interaction with patches will be written in every time step in log which could cause huge storage of log with cases with many patches (for our case, 500). I now make it as an option (default is false as it is now). This change will be very convenient for users dealing with huge projects without affect the current state of OpenFOAM.
Steps To Reproduce1. In LocalInteraction.H:
    add a new variable: Switch logAtWriteTime_;
2. In LocalInteraction.C:
    read the value of logAtWriteTime_ from dict or default false (line 94)
    move the write operation into an "if". (line 449 - 489)
    
Additional Informationfiles of changes are attached. Other patch interaction model could be modified the same if you feel needed.
TagsNo tags attached.

Activities

nguyenhung97

2024-11-25 07:35

reporter  

LocalInteraction_new.C (14,525 bytes)   
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     | Website:  https://openfoam.org
    \\  /    A nd           | Copyright (C) 2011-2024 OpenFOAM Foundation
     \\/     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/>.

\*---------------------------------------------------------------------------*/

#include "LocalInteraction.H"
#include "wordAndDictionary.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{

struct wordReAndDictionary
:
    public Tuple2<wordRe, dictionary>
{
    using Tuple2<wordRe, dictionary>::Tuple2;

    wordReAndDictionary();

    wordReAndDictionary(Istream& is);
};


inline Istream& operator>>(Istream& is, wordReAndDictionary& wd)
{
    wd.first() = wordRe(is);
    dictionary d(is);
    wd.second().transfer(d);
    return is;
}


inline Ostream& operator<<(Ostream& os, const wordReAndDictionary& wd)
{
    return os << wd.first() << token::SPACE << wd.second();
}


inline wordReAndDictionary::wordReAndDictionary()
{}


inline wordReAndDictionary::wordReAndDictionary(Istream& is)
{
    is >> *this;
}

}


// * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * * //

template<class CloudType>
Foam::LocalInteraction<CloudType>::LocalInteraction
(
    const dictionary& dict,
    CloudType& cloud
)
:
    PatchInteractionModel<CloudType>(dict, cloud, typeName),
    patchInteractionTypes_
    (
        this->owner().mesh().boundaryMesh().size(),
        PatchInteractionModel<CloudType>::itOther
    ),
    patchEs_(this->owner().mesh().boundaryMesh().size(), NaN),
    patchMus_(this->owner().mesh().boundaryMesh().size(), NaN),
    nEscape_(this->owner().mesh().boundaryMesh().size(), 0),
    massEscape_(this->owner().mesh().boundaryMesh().size(), scalar(0)),
    nStick_(this->owner().mesh().boundaryMesh().size(), 0),
    massStick_(this->owner().mesh().boundaryMesh().size(), scalar(0)),
    writeFields_(this->coeffDict().lookupOrDefault("writeFields", false)),
    logAtWriteTime_(this->coeffDict().lookupOrDefault("logAtWriteTime", false)),
    massEscapePtr_(nullptr),
    massStickPtr_(nullptr)
{
    const polyBoundaryMesh& patches = this->owner().mesh().boundaryMesh();

    if (writeFields_)
    {
        const word massEscapeName(this->owner().name() + ":massEscape");
        const word massStickName(this->owner().name() + ":massStick");

        Info<< "    Interaction fields will be written to " << massEscapeName
            << " and " << massStickName << endl;

        (void)massEscape();
        (void)massStick();
    }
    else
    {
        Info<< "    Interaction fields will not be written" << endl;
    }

    // Get the patch-settings dictionaries
    dictionary patchesDict;
    if (this->coeffDict().isDict("patches"))
    {
        patchesDict = this->coeffDict().subDict("patches");
    }
    else
    {
        const List<wordReAndDictionary> patchNameAndDicts
        (
            this->coeffDict().lookup("patches")
        );

        forAll(patchNameAndDicts, dicti)
        {
            patchesDict.set
            (
                keyType(string(patchNameAndDicts[dicti].first())),
                patchNameAndDicts[dicti].second()
            );
        }
    }

    // Read the patch settings
    wordList unspecifiedNonConstraintPatches;
    forAll(patches, patchi)
    {
        const word& patchName = patches[patchi].name();

        const bool havePatchDict = patchesDict.found(patchName);

        const bool patchIsConstraint =
            polyPatch::constraintType(patches[patchi].type());

        // No settings for constrained patch. No model.
        if (!havePatchDict && patchIsConstraint)
        {
            patchInteractionTypes_[patchi] =
                PatchInteractionModel<CloudType>::itNone;
            continue;
        }

        // No settings for non-constrained patch. Error.
        if (!havePatchDict && !patchIsConstraint)
        {
            unspecifiedNonConstraintPatches.append(patches[patchi].name());
            continue;
        }

        const dictionary& patchDict = patchesDict.subDict(patchName);

        // Settings for constrained patch. Ignored unless "patchType" is
        // correctly specified.
        if (havePatchDict && patchIsConstraint)
        {
            if (!patchDict.found("patchType"))
            {
                patchInteractionTypes_[patchi] =
                    PatchInteractionModel<CloudType>::itNone;
                continue;
            }

            const word patchType = patchDict.lookup<word>("patchType");

            if (patchType != patches[patchi].type())
            {
                FatalErrorInFunction
                    << "Type " << patchType
                    << " specified for patch " << patchName
                    << " does not match the patch type "
                    << patches[patchi].type() << exit(FatalError);
            }
        }

        // Read and set the interaction model
        const word itName = patchDict.lookup<word>("type");
        const interactionType it = this->wordToInteractionType(itName);

        if (it == PatchInteractionModel<CloudType>::itOther)
        {
            FatalErrorInFunction
                << "Unknown patch interaction type "
                << itName << " for patch " << patchName
                << ". Valid types are:"
                << PatchInteractionModel<CloudType>::interactionTypeNames_
                << nl << exit(FatalError);
        }

        patchInteractionTypes_[patchi] = it;

        if (it == PatchInteractionModel<CloudType>::itRebound)
        {
            patchEs_[patchi] = patchDict.lookupOrDefault<scalar>("e", 1);
            patchMus_[patchi] = patchDict.lookupOrDefault<scalar>("mu", 0);
        }
    }

    // Error if interactions are unspecified for non-constraint patches
    if (!unspecifiedNonConstraintPatches.empty())
    {
        FatalErrorInFunction
            << "No interaction type was specified for non-constraint patches: "
            << unspecifiedNonConstraintPatches
            << exit(FatalError);
    }
}


template<class CloudType>
Foam::LocalInteraction<CloudType>::LocalInteraction
(
    const LocalInteraction<CloudType>& pim
)
:
    PatchInteractionModel<CloudType>(pim),
    patchInteractionTypes_(pim.patchInteractionTypes_),
    patchEs_(pim.patchEs_),
    patchMus_(pim.patchMus_),
    nEscape_(pim.nEscape_),
    massEscape_(pim.massEscape_),
    nStick_(pim.nStick_),
    massStick_(pim.massStick_),
    writeFields_(pim.writeFields_),
    logAtWriteTime_(pim.logAtWriteTime_),
    massEscapePtr_(nullptr),
    massStickPtr_(nullptr)
{}


// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //

template<class CloudType>
Foam::LocalInteraction<CloudType>::~LocalInteraction()
{}


// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //

template<class CloudType>
Foam::volScalarField& Foam::LocalInteraction<CloudType>::massEscape()
{
    if (!massEscapePtr_.valid())
    {
        const fvMesh& mesh = this->owner().mesh();

        massEscapePtr_.reset
        (
            new volScalarField
            (
                IOobject
                (
                    this->owner().name() + ":massEscape",
                    mesh.time().name(),
                    mesh,
                    IOobject::READ_IF_PRESENT,
                    IOobject::AUTO_WRITE
                ),
                mesh,
                dimensionedScalar(dimMass, 0)
            )
        );
    }

    return massEscapePtr_();
}


template<class CloudType>
Foam::volScalarField& Foam::LocalInteraction<CloudType>::massStick()
{
    if (!massStickPtr_.valid())
    {
        const fvMesh& mesh = this->owner().mesh();

        massStickPtr_.reset
        (
            new volScalarField
            (
                IOobject
                (
                    this->owner().name() + ":massStick",
                    mesh.time().name(),
                    mesh,
                    IOobject::READ_IF_PRESENT,
                    IOobject::AUTO_WRITE
                ),
                mesh,
                dimensionedScalar(dimMass, 0)
            )
        );
    }

    return massStickPtr_();
}


template<class CloudType>
bool Foam::LocalInteraction<CloudType>::correct
(
    typename CloudType::parcelType& p,
    const polyPatch& pp,
    bool& keepParticle
)
{
    const label patchi = pp.index();

    if (isA<processorPolyPatch>(pp))
    {
        return false;
    }

    switch (patchInteractionTypes_[patchi])
    {
        case PatchInteractionModel<CloudType>::itNone:
        {
            return false;
        }

        case PatchInteractionModel<CloudType>::itEscape:
        {
            const scalar dm = p.mass()*p.nParticle();

            keepParticle = false;
            p.moving() = false;
            p.U() = Zero;
            nEscape_[patchi] ++;
            massEscape_[patchi] += dm;

            if (writeFields_)
            {
                const label patchFacei = pp.whichFace(p.face());
                massEscape().boundaryFieldRef()[patchi][patchFacei] += dm;
            }

            return true;
        }

        case PatchInteractionModel<CloudType>::itStick:
        {
            const scalar dm = p.mass()*p.nParticle();

            keepParticle = true;
            p.moving() = false;
            p.U() = Zero;
            nStick_[patchi] ++;
            massStick_[patchi] += dm;

            if (writeFields_)
            {
                const label patchFacei = pp.whichFace(p.face());
                massStick().boundaryFieldRef()[patchi][patchFacei] += dm;
            }

            return true;
        }

        case PatchInteractionModel<CloudType>::itRebound:
        {
            keepParticle = true;
            p.moving() = true;

            vector nw, Up;
            this->owner().patchData(p, pp, nw, Up);

            // Make motion relative to patch velocity
            p.U() -= Up;

            const scalar Un = p.U() & nw;
            const vector Ut = p.U() - Un*nw;

            if (Un > 0)
            {
                p.U() -= (1 + patchEs_[patchi])*Un*nw;
            }

            p.U() -= patchMus_[patchi]*Ut;

            // Return velocity to global space
            p.U() += Up;

            return true;
        }

        default:
        {
            return false;
        }
    }

    return false;
}


template<class CloudType>
void Foam::LocalInteraction<CloudType>::info(Ostream& os)
{
    const polyBoundaryMesh& patches = this->owner().mesh().boundaryMesh();

    // Determine the number of non-processor patches
    label nPatches = patches.size();
    for (; isA<processorPolyPatch>(patches[nPatches - 1]); nPatches --);

    // Retrieve any stored data
    labelList npe0(nPatches, 0);
    this->getModelProperty("nEscape", npe0);

    scalarList mpe0(nPatches, scalar(0));
    this->getModelProperty("massEscape", mpe0);

    labelList nps0(nPatches, 0);
    this->getModelProperty("nStick", nps0);

    scalarList mps0(nPatches, scalar(0));
    this->getModelProperty("massStick", mps0);

    // Accumulate current data
    labelList npe(SubList<label>(nEscape_, nPatches));
    Pstream::listCombineGather(npe, plusEqOp<label>());
    npe = npe + npe0;

    scalarList mpe(SubList<scalar>(massEscape_, nPatches));
    Pstream::listCombineGather(mpe, plusEqOp<scalar>());
    mpe = mpe + mpe0;

    labelList nps(SubList<label>(nStick_, nPatches));
    Pstream::listCombineGather(nps, plusEqOp<label>());
    nps = nps + nps0;

    scalarList mps(SubList<scalar>(massStick_, nPatches));
    Pstream::listCombineGather(mps, plusEqOp<scalar>());
    mps = mps + mps0;

    if (logAtWriteTime_)
    {
        if (this->writeTime())
        {
            for (label patchi = 0; patchi < nPatches; ++ patchi)
            {
                if
                (
                    patchInteractionTypes_[patchi]
                != PatchInteractionModel<CloudType>::itNone
                )
                {
                    os  << "    Parcel fate (number, mass)      : patch "
                        << this->owner().mesh().boundaryMesh()[patchi].name() << nl
                        << "      - escape                      = " << npe[patchi]
                        << ", " << mpe[patchi] << nl
                        << "      - stick                       = " << nps[patchi]
                        << ", " << mps[patchi] << nl;
                }
            }
        }
    }
    else
    {
        for (label patchi = 0; patchi < nPatches; ++ patchi)
        {
            if
            (
                patchInteractionTypes_[patchi]
            != PatchInteractionModel<CloudType>::itNone
            )
            {
                os  << "    Parcel fate (number, mass)      : patch "
                    << this->owner().mesh().boundaryMesh()[patchi].name() << nl
                    << "      - escape                      = " << npe[patchi]
                    << ", " << mpe[patchi] << nl
                    << "      - stick                       = " << nps[patchi]
                    << ", " << mps[patchi] << nl;
            }
        }
    }
    
    if (this->writeTime())
    {
        this->setModelProperty("nEscape", npe);
        nEscape_ = 0;

        this->setModelProperty("massEscape", mpe);
        massEscape_ = scalar(0);

        this->setModelProperty("nStick", nps);
        nStick_ = 0;

        this->setModelProperty("massStick", mps);
        massStick_ = scalar(0);
    }
}


// ************************************************************************* //

LocalInteraction_new.C (14,525 bytes)   
LocalInteraction_new.H (4,729 bytes)   
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     | Website:  https://openfoam.org
    \\  /    A nd           | Copyright (C) 2011-2022 OpenFOAM Foundation
     \\/     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/>.

Class
    Foam::LocalInteraction

Description
    Patch interaction specified on a patch-by-patch basis

\*---------------------------------------------------------------------------*/

#ifndef LocalInteraction_H
#define LocalInteraction_H

#include "PatchInteractionModel.H"
#include "Switch.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{
/*---------------------------------------------------------------------------*\
                      Class LocalInteraction Declaration
\*---------------------------------------------------------------------------*/

template<class CloudType>
class LocalInteraction
:
    public PatchInteractionModel<CloudType>
{
    // Private Typedefs

        //- Interaction type enumeration
        typedef
            typename PatchInteractionModel<CloudType>::interactionType
            interactionType;


    // Private Data

        // Interactions

            //- Patch interaction types
            List<interactionType> patchInteractionTypes_;

            //- Patch elasticity coefficients (for rebound)
            List<scalar> patchEs_;

            //- Patch restitution coefficients (for rebound)
            List<scalar> patchMus_;


        // Counters for particle fates

            //- Number of parcels escaped
            List<label> nEscape_;

            //- Mass of parcels escaped
            List<scalar> massEscape_;

            //- Number of parcels stuck to patches
            List<label> nStick_;

            //- Mass of parcels stuck to patches
            List<scalar> massStick_;


        //- Flag to output data as fields
        Switch writeFields_;

        //- Flag to write log at writeTime
        Switch logAtWriteTime_;
        
        //- Mass escape field
        autoPtr<volScalarField> massEscapePtr_;

        //- Mass stick field
        autoPtr<volScalarField> massStickPtr_;


public:

    //- Runtime type information
    TypeName("localInteraction");


    // Constructors

        //- Construct from dictionary
        LocalInteraction(const dictionary& dict, CloudType& owner);

        //- Construct copy from owner cloud and patch interaction model
        LocalInteraction(const LocalInteraction<CloudType>& pim);

        //- Construct and return a clone using supplied owner cloud
        virtual autoPtr<PatchInteractionModel<CloudType>> clone() const
        {
            return autoPtr<PatchInteractionModel<CloudType>>
            (
                new LocalInteraction<CloudType>(*this)
            );
        }


    //- Destructor
    virtual ~LocalInteraction();


    // Member Functions

        //- Return access to the massEscape field
        volScalarField& massEscape();

        //- Return access to the massStick field
        volScalarField& massStick();

        //- Apply velocity correction
        //  Returns true if particle remains in same cell
        virtual bool correct
        (
            typename CloudType::parcelType& p,
            const polyPatch& pp,
            bool& keepParticle
        );


        // I-O

            //- Write patch interaction info to stream
            virtual void info(Ostream& os);
};


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

} // End namespace Foam

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#ifdef NoRepository
    #include "LocalInteraction.C"
#endif

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //

LocalInteraction_new.H (4,729 bytes)   

will

2024-11-26 12:00

manager   ~0013477

If you want the logging customised for the convenience of your workflow then you will need to pay for that work. Closed pending funding.

Issue History

Date Modified Username Field Change
2024-11-25 07:35 nguyenhung97 New Issue
2024-11-25 07:35 nguyenhung97 File Added: LocalInteraction_new.C
2024-11-25 07:35 nguyenhung97 File Added: LocalInteraction_new.H
2024-11-26 12:00 will Assigned To => will
2024-11-26 12:00 will Status new => closed
2024-11-26 12:00 will Resolution open => no change required
2024-11-26 12:00 will Note Added: 0013477