CFD Online Discussion Forums

CFD Online Discussion Forums (http://www.cfd-online.com/Forums/)
-   OpenFOAM Running, Solving & CFD (http://www.cfd-online.com/Forums/openfoam-solving/)
-   -   delayed response - on the limit of groovyBC's capabilities? (http://www.cfd-online.com/Forums/openfoam-solving/104408-delayed-response-limit-groovybcs-capabilities.html)

sylvester July 9, 2012 05:00

delayed response - on the limit of groovyBC's capabilities?
 
1 Attachment(s)
Is it possible to have a patch react to the value of another patch, but only after a certain delay?

For example see the geometry depicted in de picture attached.
From the bottom of a mixing tank, fluid with a certain amount of contamination is (continuously) taken. This fluid is then processed, such that the contamination level changes. After about 30 seconds the fluid is be fed back into the tank.

My first thought was to use groovyBC, as it was helpful so many times in the past. But after having a good look on the wiki and this forum I haven't been able to find a clue on how to do this. So maybe I have to build a custom boundary condition after all.

Any suggestion will be much appreciated!

Best regards,
Sylvester

gschaider July 9, 2012 12:53

Quote:

Originally Posted by sylvester (Post 370420)
Is it possible to have a patch react to the value of another patch, but only after a certain delay?

For example see the geometry depicted in de picture attached.
From the bottom of a mixing tank, fluid with a certain amount of contamination is (continuously) taken. This fluid is then processed, such that the contamination level changes. After about 30 seconds the fluid is be fed back into the tank.

My first thought was to use groovyBC, as it was helpful so many times in the past. But after having a good look on the wiki and this forum I haven't been able to find a clue on how to do this. So maybe I have to build a custom boundary condition after all.

Any suggestion will be much appreciated!

Best regards,
Sylvester

How does the outgoing fluid determine the properties of the incoming fluid? A simple switching condition can be implemented with storedVariables (provided the state doesn't change afterwards). If you're going for something like C_in(t)=C_out(t-30): that is currently not possible. I have been thinking about delayedVariables (and they shouldn't be too hard to implement with the usual restriction "only uniform") but no concrete plans yet (A feature-request/bug-report would show that there is some demand for that and COULD speed things up)

Another possibility would be to use the pythonIntegration-functionObject and implement the delaying yourself (one possibility would be to use rrdtool to do the storage. It is specialized for that kind of thing)

I don't think that the coded-functionObject that comes with OF gives you the possibility to store date between calls to the FO and therefor won't work with this. But I could be wrong

sylvester July 10, 2012 03:18

Hi Bernhard,

Thanks for your help.

Quote:

Originally Posted by gschaider (Post 370496)
How does the outgoing fluid determine the properties of the incoming fluid? A simple switching condition can be implemented with storedVariables (provided the state doesn't change afterwards). If you're going for something like C_in(t)=C_out(t-30): that is currently not possible. I have been thinking about delayedVariables (and they shouldn't be too hard to implement with the usual restriction "only uniform") but no concrete plans yet (A feature-request/bug-report would show that there is some demand for that and COULD speed things up)

Yes, it would be something like C_in(t)=f(C_out(t-30)). I'll place a request for the storedVariables feature.

Quote:

Originally Posted by gschaider (Post 370496)
Another possibility would be to use the pythonIntegration-functionObject and implement the delaying yourself (one possibility would be to use rrdtool to do the storage. It is specialized for that kind of thing)

I have never used the pythonIntegration-functionObject, but I'll look into it. Combining it with rrdtool may well be beyond my capabilities though. Nevertheless I'll give it a try.

Quote:

Originally Posted by gschaider (Post 370496)
I don't think that the coded-functionObject that comes with OF gives you the possibility to store date between calls to the FO and therefor won't work with this. But I could be wrong

To me the coded BC never appeared more powerful, or as easy to use as groovyBC. So I did not considered before. I'll have look at it though.

If I get something working, I'll report back here.

Regards,
Sylvester

gschaider July 10, 2012 03:35

Quote:

Originally Posted by sylvester (Post 370573)
Hi Bernhard,

Thanks for your help.



Yes, it would be something like C_in(t)=f(C_out(t-30)). I'll place a request for the storedVariables feature.



I have never used the pythonIntegration-functionObject, but I'll look into it. Combining it with rrdtool may well be beyond my capabilities though. Nevertheless I'll give it a try.

I've had a quick look at the API of rrdtool: I'm afraid it is not a good choice. It doesn't keep the database in memory but on disc and access is .... weird. I thought mostly that the RoundRobin-capability would make it a good candidate

Quote:

Originally Posted by sylvester (Post 370573)
To me the coded BC never appeared more powerful, or as easy to use as groovyBC. So I did not considered before. I'll have look at it though.

As I said: I'm afraid it won't help you for your problem as it "forgets" everything between calls.

BTW: swak has a subclass (swakCoded) of it that allows to read and write swak-Variables in global namespaces. But this isn't sufficient for our purposes too I'm afraid

Quote:

Originally Posted by sylvester (Post 370573)
If I get something working, I'll report back here.

OK

sylvester July 11, 2012 05:55

Hi Bernhard,

I've got it working now.

The input concentration is calculated in a swakCoded/swakFunctionObjects. Using globalScopes this concentration is available to a standard groovyBC for the inlet patch.

The time history of the concentration is stored within the swakCoded/swakFunctionObjects using a global (fixed length) scalar. The availability of a labelList for this part would have resulted in prettier code, but this is also working.

The examples I used for this construct were 'cylinderWithSwak' for the 'swakCoded/swakFunctionObjects' part and the file 'Examples/tests/pythonIntegration/0/rand' for the 'globalScopes/groovyBC' part.

Thanks again for your help!

regards,
Sylvester

gschaider July 11, 2012 08:29

Quote:

Originally Posted by sylvester (Post 370772)
Hi Bernhard,

I've got it working now.

Great. Congratulations. Its always nice when people abuse swak for stuff that I didn't think is possible.

Quote:

Originally Posted by sylvester (Post 370772)
The input concentration is calculated in a swakCoded/swakFunctionObjects. Using globalScopes this concentration is available to a standard groovyBC for the inlet patch.

The time history of the concentration is stored within the swakCoded/swakFunctionObjects using a global (fixed length) scalar. The availability of a labelList for this part would have resulted in prettier code, but this is also working.

Just some questions:
- you mean "fixedLength scalarList", right?
- why was labelList not possible? Not "known"? Are you aware of codeInclude (see http://www.openfoam.org/docs/user/ba...8-1050004.2.11) or does this not work with the swak-FO?
- how did you get the persistence between calls? Is it possible to add member variables to the FO or did you use a static variable in the function?
- does your solution assume a fixed time-step?

Quote:

Originally Posted by sylvester (Post 370772)
The examples I used for this construct were 'cylinderWithSwak' for the 'swakCoded/swakFunctionObjects' part and the file 'Examples/tests/pythonIntegration/0/rand' for the 'globalScopes/groovyBC' part.

Anyhow. I'll go ahead with the delayed thing once I have time.

Would you like to contribute your example?

Bernhard

sylvester July 11, 2012 09:07

Quote:

Originally Posted by gschaider (Post 370808)
- you mean "fixedLength scalarList", right?

Never heard of them. For my (ugly) solution see the timeList and concentrationList definition in the code below.

Quote:

Originally Posted by gschaider (Post 370808)
- why was labelList not possible? Not "known"? Are you aware of codeInclude (see http://www.openfoam.org/docs/user/ba...8-1050004.2.11) or does this not work with the swak-FO?

TimeList and concentrationList only accepted type scalar (or vector), see code below.
I was not aware of codeInclude.

Quote:

Originally Posted by gschaider (Post 370808)
- how did you get the persistence between calls? Is it possible to add member variables to the FO or did you use a static variable in the function?

"persistance between calls": I don't even know what that means.

Quote:

Originally Posted by gschaider (Post 370808)
- does your solution assume a fixed time-step?

As you'll see in the code, this part is not finished yet. I'm already storing the (average) concentration every time data is written to disk. And I have verified I can access this data at a later iteration. Next I will add a mechanism that will use linear interpolation between stored concentration value, plus some additional processing function.


Quote:

Originally Posted by gschaider (Post 370808)
Anyhow. I'll go ahead with the delayed thing once I have time.

For me the urgency level has dropped quite a few levels now. Let me know if you need somebody to test it, though.

Regards,
Sylvester

from controlDict:
Code:

libs (
    "libswakFunctionObjects.so"
    "libsimpleSwakFunctionObjects.so"
    "libgroovyStandardBCs.so"
);

functions
{
    addTimeList {
        type addGlobalVariable;
        globalName timeList;
        globalScope concentrationResults;
        valueType scalar;
        value 999999{0};
        isSingleValue false;
    }
    addTimeListLength {
        type addGlobalVariable;
        globalName timeListLength;
        globalScope concentrationResults;
        valueType scalar;
        value 0;
        isSingleValue true;
    }
    addConcentrationList {
        type addGlobalVariable;
        globalName concentrationList;
        globalScope concentrationResults;
        valueType scalar;
        value 999999{0};
        isSingleValue false;
    }
    addInConcentration {
        type addGlobalVariable;
        globalName inConcentration;
        globalScope concentrationResults;
        valueType scalar;
        value 0;
        isSingleValue true;
    }

    concentrationFunction
    {
        // Load the library containing the 'coded' functionObject
        functionObjectLibs ("libswakFunctionObjects.so");
        type swakCoded;
        codedToSwakNamespace concentrationResults;
        codedToSwakVariables
        (
            timeList
            timeListLength
            concentrationList
            inConcentration
        );
        swakToCodedNamespaces (concentrationResults);
        code
        #{
            const volScalarField& T = mesh().lookupObject<volScalarField>("T");

            label outPatch = mesh().boundaryMesh().findPatchID("outlet");
            label inPatch = mesh().boundaryMesh().findPatchID("inlet");

            scalar delay=30.;

            dimensionedScalar Concentration
            (
                "Concentration",
                dimensionSet(0, 0, 0, 1, 0),
                gSum
                (
                    T.boundaryField()[outPatch] * mesh().magSf().boundaryField()[outPatch]
                )
                /
                gSum
                (
                    mesh().magSf().boundaryField()[outPatch]
                )
            );

            if (mesh().time().outputTime())
            {
                timeList[++timeListLength] = mesh().time().value();
                concentrationList[timeListLength] = Concentration.value();
                scalar procesTime = timeList[timeListLength] - delay;

                if (procesTime < timeList[0])
                {
//                    Info << "No data yet" << endl;
                    inConcentration = 1.0;
                }
                else
                {
//                    Info << "Woohoo data!" << endl;
                    inConcentration = 1.0 + max(concentrationList[timeListLength],0);
                }
            }
        #};
    }
}

from 0/T:
Code:

    inlet
    {
        type            groovyBC;
        value          uniform 1;
        globalScopes ( concentrationResults );
        valueExpression "inConcentration";
    }


gschaider July 11, 2012 13:43

Quote:

Originally Posted by sylvester (Post 370820)
from controlDict:
Code:

libs (
    "libswakFunctionObjects.so"
    "libsimpleSwakFunctionObjects.so"
    "libgroovyStandardBCs.so"
);

functions
{
    addTimeList {
        type addGlobalVariable;
        globalName timeList;
        globalScope concentrationResults;
        valueType scalar;
        value 999999{0};
        isSingleValue false;
    }
    addTimeListLength {
        type addGlobalVariable;
        globalName timeListLength;
        globalScope concentrationResults;
        valueType scalar;
        value 0;
        isSingleValue true;
    }
    addConcentrationList {
        type addGlobalVariable;
        globalName concentrationList;
        globalScope concentrationResults;
        valueType scalar;
        value 999999{0};
        isSingleValue false;
    }
    addInConcentration {
        type addGlobalVariable;
        globalName inConcentration;
        globalScope concentrationResults;
        valueType scalar;
        value 0;
        isSingleValue true;
    }

    concentrationFunction
    {
        // Load the library containing the 'coded' functionObject
        functionObjectLibs ("libswakFunctionObjects.so");
        type swakCoded;
        codedToSwakNamespace concentrationResults;
        codedToSwakVariables
        (
            timeList
            timeListLength
            concentrationList
            inConcentration
        );
        swakToCodedNamespaces (concentrationResults);
        code
        #{
            const volScalarField& T = mesh().lookupObject<volScalarField>("T");

            label outPatch = mesh().boundaryMesh().findPatchID("outlet");
            label inPatch = mesh().boundaryMesh().findPatchID("inlet");

            scalar delay=30.;

            dimensionedScalar Concentration
            (
                "Concentration",
                dimensionSet(0, 0, 0, 1, 0),
                gSum
                (
                    T.boundaryField()[outPatch] * mesh().magSf().boundaryField()[outPatch]
                )
                /
                gSum
                (
                    mesh().magSf().boundaryField()[outPatch]
                )
            );

            if (mesh().time().outputTime())
            {
                timeList[++timeListLength] = mesh().time().value();
                concentrationList[timeListLength] = Concentration.value();
                scalar procesTime = timeList[timeListLength] - delay;

                if (procesTime < timeList[0])
                {
//                    Info << "No data yet" << endl;
                    inConcentration = 1.0;
                }
                else
                {
//                    Info << "Woohoo data!" << endl;
                    inConcentration = 1.0 + max(concentrationList[timeListLength],0);
                }
            }
        #};
    }
}

from 0/T:
Code:

    inlet
    {
        type            groovyBC;
        value          uniform 1;
        globalScopes ( concentrationResults );
        valueExpression "inConcentration";
    }


Now THAT is a wickedly cool solution. Didn't think of using a global variable for storing the data. Honestly: wasn't even aware that I allowed non-uniform specification. But as I think of it: of course. That is needed for restarting

Quote:

Originally Posted by sylvester (Post 370820)
Never heard of them. For my (ugly) solution see the timeList and concentrationList definition in the code below.


TimeList and concentrationList only accepted type scalar (or vector), see code below.
I was not aware of codeInclude.

That was all under the assumption that you stored the data in the functionObject. So codeInclude won't help you here.

label as a list type is not supported by swak because there is no such thing as a volLabelField

Quote:

Originally Posted by sylvester (Post 370820)
"persistance between calls": I don't even know what that means.

That means that the functionObject stores data between two consecutive function calls

Quote:

Originally Posted by sylvester (Post 370820)
As you'll see in the code, this part is not finished yet. I'm already storing the (average) concentration every time data is written to disk. And I have verified I can access this data at a later iteration. Next I will add a mechanism that will use linear interpolation between stored concentration value, plus some additional processing function.

OK. One possibility for "finer" granularity would be to define yourself a deltaT and a value "lastWritten" and new data is only added when time>lastWritten+deltaT. But I'm confident you'll find a way yourself

Quote:

Originally Posted by sylvester (Post 370820)
For me the urgency level has dropped quite a few levels now. Let me know if you need somebody to test it, though.

Don't be offended but your urgency is of little relevance to me if you're not a client ;)


All times are GMT -4. The time now is 13:01.