CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Running, Solving & CFD (https://www.cfd-online.com/Forums/openfoam-solving/)
-   -   Terminate simulation based on probe (https://www.cfd-online.com/Forums/openfoam-solving/110446-terminate-simulation-based-probe.html)

Bernhard December 11, 2012 10:25

Terminate simulation based on probe
 
I am running a specific a large set of parameter variations of a specific case (go pyFoam!). The case is using a transient solver, but will eventually result in a steady state simulation. I want to keep that this way.

Based on some probes, I can a posteriori conclude when the steady state was reached. Now, I want to terminate the simulation (with writing output), based on the probes during runTime. This will save me a lot of computational time.

I am not sure how to proceed with this. I am thinking in the direction of some functionObject, but I wonder if anything in this respect has been done already.

I am not afraid to implement things, so any hints or guidance in that direction is very welcome. Also other remarks, hints, tips, suggestions, comments, notes and answers are highly appreciated!

ganeshv December 11, 2012 15:03

Take a look at the panicDump functionObject

http://scicomp.stackexchange.com/que...-a-given-range

http://openfoamwiki.net/index.php/Co...unctionObjects

Bernhard December 11, 2012 15:41

Thanks, I will have a look into it. I think it is not completely what I need, but definitely a good starting point for further implementation.

simpomann December 12, 2012 10:06

hi
 
Hi,

I did something similiar using a bash script.
Basically it reads out the lines of the probe alpha file, creates an average (out of the three probes i used) and terminates interFoam if a condition is met (in this case average=0.7). openFoam is started via a script called Allrun in background and every 5 second there is a check for the condition...
Unluckily I cant publish the code as I created it for my employer :(

Some hints:

- set a killswitch variable that changes from 0 to 1 when a condition is met (in my case was the average of three probe alpha values >=0.7)
- a basic structure

initialising killswitch, condition etc
start openfoam application in background, e.g. "sh Allrun &"
while [condition is not met]
while read inputline #useful function to grab values from probe file

time="$(echo $inputline | cut -d' ' -f1)"
alpha1="$(echo $inputline | cut -d' ' -f2)"
alpha2="$(echo $inputline | cut -d' ' -f3)"
alpha3="$(echo $inputline | cut -d' ' -f4)"


some stuff about string/integer conversion

if
condition not met : killswitch stays 0
condition is met: killswitch to 1
killall "solvername"
fi

sleep 5
done < path/to/probe/file
done


A useful function for mathematics in bash is |bc
e.g.

final=$(echo "scale=4; ($a+$b+$c)/$nrOfProbes"|bc -l)

the variable final is the average of variables a+b+c, divided by the nrOfProbes (another variable).

Well sorry for not showing up with real code, but I can't. Anyway not sure if this is what you are looking for because i dont know about pyFoam.
Good luck!
Simon

Something that came to my mind: This will leave you with the output from the last normally processed timestep... If you want the real last moment captured, I guess you have to do the following
When the condition is met:
- change writeInterval in controlDict to something super small, what will cause openFoam to write a folder with the timestep data immediately
- terminate process than with killall (I know, its like opening a coke can with a chainsaw, but hey; after the solver termination the rest of your script will run through, e.g. yPlus calculation, foamToVTK or whatever is following after the solution)

Another hint:
- This also will create average values from the header lines of your probe file, for me was no problem as coordinates were super small (so it never met my cancel-condition), but depending on your probe's coordinates you have to find a solution for this (I created an emergency switch that put all read values >1 to 0, because I was processing the alpha field what made it fairly easy)

kwardle December 12, 2012 10:51

There is also the runTime.writeAndEnd() function which will immediately write the data fields and stop the simulation when called. This may be useful but you will have to trigger it in the solver based on your probe analysis somehow. If you can live with runTimeModifiable on (I cannot) then a flag in controlDict is an option. Just a few thoughts.

Bernhard December 12, 2012 11:16

Dear Simon, thanks for this extensive answer. I did not think about a solution like this, but I think it can work. Did you know about the writeNext or stopNow options for stopAt? That may simplify your scripts a bit.

But I am actually looking for a robust approach. With your approach, if I just rerun the solver, it will not check for this criteria again right?
Also, if I have multiple instances of the same solver running, then I would kill them all, which is also undesired.

Bernhard December 12, 2012 11:22

Quote:

Originally Posted by kwardle (Post 397181)
There is also the runTime.writeAndEnd() function which will immediately write the data fields and stop the simulation when called. This may be useful but you will have to trigger it in the solver based on your probe analysis somehow. If you can live with runTimeModifiable on (I cannot) then a flag in controlDict is an option. Just a few thoughts.

The trick is in 'somehow', I still think functionObjects are the way to go here, but I am experiencing some coding issues here :)

Bernhard December 13, 2012 10:27

For future reference, I was able to reproduce the panicDump behavior with codedFunctionObjects

Code:

    codedTest
    {
        type coded;
        functionObjectLibs
        (
            "libutilityFunctionObjects.so"
        );
        redirectType    probeFinishControl;
        outputControl  timeStep;
        minP            0.04;

        code
        #{
          const volScalarField& p = mesh().lookupObject<volScalarField>("p");
          Info << mesh().time().value() << " " << average(p).value() << endl;
          if ( average(p).value() < $minP )
          {
              bool result=const_cast<Time&>(mesh().time()).writeNow();
              FatalErrorIn("Stopped")
                  << "Bla" << endl
                  << exit(FatalError);
          }
        #};
    }

Of course probing is necessary, but this is a starting point :)

Also, I would like to advertise this related topic: http://www.cfd-online.com/Forums/ope...ionobject.html

Bernhard December 13, 2012 11:36

To continue my monologue. For the cavity-case and icoFoam I was able to get to the converged solution with the function I posted below.

Please note that this is only working for monotic increasing or decreasing convergence at a point, so it is far from a solid check, but, it is a starting point :)

Code:

  probeFinishControl
    {
        type coded;
        functionObjectLibs
        (
            "libutilityFunctionObjects.so"
        );
        redirectType    probeFinishControl;
        outputControl  timeStep;
        fieldName      p;
        code
        #{
          const volScalarField& p = mesh().lookupObject<volScalarField>("$fieldName");
         
          scalar probe0(p.oldTime()[1]);
          scalar probe1(p[1]);
          scalar diff(probe0-probe1);
          Info << probe0 << endl << probe1 << endl;
          Info << fabs(diff) << endl;
          Info << mesh().time().timeIndex() << endl;

          if ( fabs(diff) < 1.e-7 && mesh().time().timeIndex() > 10 )
          {
              const_cast<Time&>(mesh().time()).writeNow();
              FatalErrorIn("probeFinishControl")
                  << "Probe on testpoint for $fieldName not changing" << endl
                  << exit(FatalError);
          }
        #};
    }


gschaider December 23, 2012 06:11

Quote:

Originally Posted by Bernhard (Post 397380)
To continue my monologue. For the cavity-case and icoFoam I was able to get to the converged solution with the function I posted below.

Please note that this is only working for monotic increasing or decreasing convergence at a point, so it is far from a solid check, but, it is a starting point :)

Code:

  probeFinishControl
    {
        type coded;
        functionObjectLibs
        (
            "libutilityFunctionObjects.so"
        );
        redirectType    probeFinishControl;
        outputControl  timeStep;
        fieldName      p;
        code
        #{
          const volScalarField& p = mesh().lookupObject<volScalarField>("$fieldName");
         
          scalar probe0(p.oldTime()[1]);
          scalar probe1(p[1]);
          scalar diff(probe0-probe1);
          Info << probe0 << endl << probe1 << endl;
          Info << fabs(diff) << endl;
          Info << mesh().time().timeIndex() << endl;

          if ( fabs(diff) < 1.e-7 && mesh().time().timeIndex() > 10 )
          {
              const_cast<Time&>(mesh().time()).writeNow();
              FatalErrorIn("probeFinishControl")
                  << "Probe on testpoint for $fieldName not changing" << endl
                  << exit(FatalError);
          }
        #};
    }


Just one possible way to get the sampling done: in swak there is a variant of the coded-functionObject called swakCoded that can be "fed" with the values of "swak global variables". So you could create the probes with swak, feed their values into a global variable and then investigate that in the (swak)Coded-FO. For the other problem that you have: that you can't have "member variables" in the coded-FO that keep their values between timesteps: have a look at what happens to local variables when they are declared static

Bernhard December 23, 2012 06:44

Thanks for your suggestions. Using a swak kind of probe would allow for a much nicer control of the probing location.

I have to test the static declaration, in the coded FO it will not work as far as I understand the C++. I see the possibilities when writing an own derived FO however. I should have thought of it.

Thanks again.

gschaider December 23, 2012 07:49

Quote:

Originally Posted by Bernhard (Post 398766)
Thanks for your suggestions. Using a swak kind of probe would allow for a much nicer control of the probing location.

I have to test the static declaration, in the coded FO it will not work as far as I understand the C++. I see the possibilities when writing an own derived FO however. I should have thought of it.

Thanks again.

Static local variables in functions should work. That is old-school C-behaviour and works inside of methods too (which basically the snipplet in a coded-FO is)

Alex2 September 8, 2014 10:49

Hallo,

I'd like to terminate my simulation based on temperature probes. For this purpose I create some probes with createSampledSet. I want to save these probes in a global variable with swakCoded and write a termination criterion. My problem is up to now, that I don't know how to get the probe values to the global variable. Is there an example?

Thank's for your help in advance

gschaider September 8, 2014 14:11

Quote:

Originally Posted by Alex2 (Post 509528)
Hallo,

I'd like to terminate my simulation based on temperature probes. For this purpose I create some probes with createSampledSet. I want to save these probes in a global variable with swakCoded and write a termination criterion. My problem is up to now, that I don't know how to get the probe values to the global variable. Is there an example?

Thank's for your help in advance

Example for using global variables would be Examples/groovyBC/fillingTheDam (the variables are used in a groovyBC but set in the controlDict with calculateGlobalVariables)

For your purposed you might not even need the variables. There is (in the simpleSwakFunctionObjects - or was it swakSimpleFunctionObjects. I keep forgetting) a FO called writeAndEndSwakExpression that gracefully ends the run if an expression is true (in your case "valueType set")

For an explained example on global variables see my "Programming swak"-presentation from this years workshop in Zagreb (it is linked from the swak-Wiki-page)

Alex2 September 9, 2014 07:04

Code:

stopIfNoChange {
                type writeAndEndSwakExpression;
                valueType set;
                logicalExpression "(diffT1 < threshold) || (diffT2 < threshold)";
                logicalAccumulation and;
        setName probePoints;    //my problems start here: how can I define the probes?
        set {
            type cloud;
            axis xyz;
            points (
                (0.25 0.05 0.4)
                (0.25 0.225 0.4)
            );

                variables (
            "T1{set 'probePoints[1]}=sum(T);"  //How can I access the probe values?
            "T1fter{set 'probePoints[1]}=sum(T);"
            "T2{set 'probePoints[2]}=sum(T);"
            "T2fter{set 'probePoints[2]}=sum(T);"
                        "diffT1=mag(T1fter-T1);"
                        "diffT2=mag(T2fter-T2);"
                        "threshold=0.5;"
                );
                delayedVariables (
                    {
                        name T1fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    {
                        name T2fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    );
                verbose true;
                outputControlMode timestep;
                outputInterval 1;
                    }

Hallo Bernhard,

thank's for your advise to use writeAndEndSwakExpression FO, but I still have some problems to implement and access the coordinates/values of my probes. I haven't found an example (,yet), how to use writeAndEndSwakExpression FO with valueType set;. Could you please give me a hint or an example?

Thank's in advance

gschaider September 9, 2014 16:33

Quote:

Originally Posted by Alex2 (Post 509644)
Code:

stopIfNoChange {
                type writeAndEndSwakExpression;
                valueType set;
                logicalExpression "(diffT1 < threshold) || (diffT2 < threshold)";
                logicalAccumulation and;
        setName probePoints;    //my problems start here: how can I define the probes?
        set {
            type cloud;
            axis xyz;
            points (
                (0.25 0.05 0.4)
                (0.25 0.225 0.4)
            );

                variables (
            "T1{set 'probePoints[1]}=sum(T);"  //How can I access the probe values?
            "T1fter{set 'probePoints[1]}=sum(T);"
            "T2{set 'probePoints[2]}=sum(T);"
            "T2fter{set 'probePoints[2]}=sum(T);"
                        "diffT1=mag(T1fter-T1);"
                        "diffT2=mag(T2fter-T2);"
                        "threshold=0.5;"
                );
                delayedVariables (
                    {
                        name T1fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    {
                        name T2fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    );
                verbose true;
                outputControlMode timestep;
                outputInterval 1;
                    }

Hallo Bernhard,

thank's for your advise to use writeAndEndSwakExpression FO, but I still have some problems to implement and access the coordinates/values of my probes. I haven't found an example (,yet), how to use writeAndEndSwakExpression FO with valueType set;. Could you please give me a hint or an example?

Thank's in advance

Use the createSampledSet-FO to create the sampled set probePoints separately.

As your value type is already "set" on probePoints you don't need the {set'probePoints} in the variables-section. The variables will then store the values in one array. It is not possible to to access the values separately but all the expressions are "vectorized". But this is not a problem for your application. The logical expression would be something like "TDiff<threshold" and the logicalAccumulation would be "or" (that would give the same semantics your current expression gives: if the difference on ANY point falls below 0.5 -> terminate run)

Alex2 September 10, 2014 11:43

Code:

        stopIfNoChange {
                type writeAndEndSwakExpression;
                valueType set;
                logicalExpression "(diffT1 < threshold)";
                logicalAccumulation or; 
        setName monitorpoints;
        set {
            type swakRegistryProxy;
            axis y;
            setName probePoints;
            }
                variables (
            "T1=T;"
            "T1fter=T;"
                        "diffT1=mag(T1fter-T1);"
                        "threshold=0.5;"
                );
                delayedVariables (
                    {
                        name T1fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    );
                verbose true;
                outputControlMode timeStep;
                outputInterval 1;
                    }

  createProbes
        {
        type createSampledSet;
        outputControl timeStep;
        outputInterval 1;
        setName probePoints;
        set {
            type cloud;
            axis y;
            points (
                (0.25 0.05 0.4)
                (0.25 0.225 0.4)
            );

        }
    }

Hallo Bernhard,

thank's for your help. I try to use the createSampledSet FO now (see code above), but unfortunately it still doesn't work. I get the following error message:
probePoints not found in table. Valid entries: 0()

Can you tell me, what I have to change?

gschaider September 10, 2014 12:21

Quote:

Originally Posted by Alex2 (Post 509875)
Code:

        stopIfNoChange {
                type writeAndEndSwakExpression;
                valueType set;
                logicalExpression "(diffT1 < threshold)";
                logicalAccumulation or; 
        setName monitorpoints;
        set {
            type swakRegistryProxy;
            axis y;
            setName probePoints;
            }
                variables (
            "T1=T;"
            "T1fter=T;"
                        "diffT1=mag(T1fter-T1);"
                        "threshold=0.5;"
                );
                delayedVariables (
                    {
                        name T1fter;
                        delay 2500;
                        storeInterval 1;
                        startupValue "1";
                    }
                    );
                verbose true;
                outputControlMode timeStep;
                outputInterval 1;
                    }

  createProbes
        {
        type createSampledSet;
        outputControl timeStep;
        outputInterval 1;
        setName probePoints;
        set {
            type cloud;
            axis y;
            points (
                (0.25 0.05 0.4)
                (0.25 0.225 0.4)
            );

        }
    }

Hallo Bernhard,

thank's for your help. I try to use the createSampledSet FO now (see code above), but unfortunately it still doesn't work. I get the following error message:
probePoints not found in table. Valid entries: 0()

Can you tell me, what I have to change?

You don't do much programming, do you? (That is nothing to be ashamed of)

Because for people how do programming the Mantra is "usually things happen in the order in which they are written down". And the functions-entry in OpenFOAM is a bit like programming

Move createProbes in front

Alex2 September 11, 2014 10:54

Hallo Bernhard,

thank you very much for your help, it seems to work.


All times are GMT -4. The time now is 20:16.