CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Post-Processing (https://www.cfd-online.com/Forums/openfoam-post-processing/)
-   -   snGradCorrection (https://www.cfd-online.com/Forums/openfoam-post-processing/107086-sngradcorrection.html)

eskila September 17, 2012 08:32

snGradCorrection
 
Hello,
I am trying to modify a utility to get the normal gradient of a scalar field at boundaries. I was getting some strange results from using fvc::snGrad, and i read in the Programmers Guide that one might benefit from using fvc::snGradCorrection if the mesh is not orthogonal (which is the case here). I tried this, but when compiling the utility I get the error:

error: ‘snGradCorrection’ is not a member of ‘Foam::fvc’

I'm a beginner with OpenFOAM, and haven't delved too deeply into its code yet, so I'm a little lost on how to find out what I'm doing wrong. Any help will be appreciated.

bigphil September 17, 2012 09:30

Hi,

there is no fvc::snGradCorrection, but you can use fvc::snGrad and then set snGradSchemes to corrected in your fvSchemes. This will calculate the surface normal gradient with non-orthogonal correction.

As regards snGrad at the boundaries, by default OpenFOAM sets non-orthogonal correction to zero at the boundary (see Jasak Thesis) so the accuracy is only good on orthogonal grids. If you do need correction at the boundaries, you need to implement custom boundary conditions with non-orthogonal correction.

Philip

eskila September 17, 2012 10:33

Let me see if i've understood you:
fvc::snGrad may be corrected for non-orthogonal meshes, but it will be no use for me if i'm only interested in the boundaries?

snGradSchemes in the system/fvSchemes of my case was already set to "corrected". Is this what is used by my custom utility?

bigphil September 17, 2012 11:07

Quote:

Originally Posted by eskila (Post 382166)
snGradSchemes in the system/fvSchemes of my case was already set to "corrected". Is this what is used by my custom utility?

When you use fvc::snGrad it checks your fvScheme for what method to use. If it finds corrected then it will use non-orthogonal correction.

Quote:

Originally Posted by eskila (Post 382166)
Let me see if i've understood you:
fvc::snGrad may be corrected for non-orthogonal meshes, but it will be no use for me if i'm only interested in the boundaries?

Each boundary patch can implement its own method to calculate the boundary snGrad so fvc::snGrad uses the values calculated by the boundary fvPatchField. So if you mesh contains fixedValue patches, then snGrad is given by (code taken from fvPatchField.C):
Code:

00176 // Return gradient at boundary
00177 template<class Type>
00178 Foam::tmp<Foam::Field<Type> > Foam::fvPatchField<Type>::snGrad() const
00179 {
00180    return (*this - patchInternalField())*patch_.deltaCoeffs();
00181 }

As can be seen, this assumes that the cell is orthogonal to the boundary.

Therefore if you are interested in orthogonal correction at the boundaries, you could implement a custom boundary condition where you define the snGrad as (taken from fixedDisplacementFvPatchVectorField.C found here):
Code:

115    const fvPatchField<tensor>& gradField =
 116        patch().lookupPatchField<volTensorField, tensor>
 117        (
 118            "grad(" +fieldName_ + ")"
 119        );
 120
 121    vectorField n = this->patch().nf();
 122    vectorField delta = this->patch().delta();
 123
 124    //- correction vector
 125    vectorField k = delta - n*(n&delta);
 126
 127    return
 128    (
 129        *this
 130      - (patchInternalField() + (k&gradField.patchInternalField()))
 131      )*this->patch().deltaCoeffs();

However, I believe non-orthogonal correction has been set to zero for a reason (for fluids anyway, solids need this correction).

Philip

sh.d August 30, 2013 06:52

corrected snGradient
 
Hi
i want to discrete momentom Eqn and i need formulation of corrected sngradient in OF.
please help me

randolph October 15, 2018 22:05

Philip,

What could be the reason you think?

Thanks,
Rdf

bigphil October 17, 2018 07:05

Hi Rdf,

I am not sure of the reason; for the diffusion operator, it can make a big difference e.g. look at the gradT field with laplacianFoam on a mesh with non-orthogonal cells near the boundary.

In fact, as far as I know, some forks of OpenFOAM (e.g. Caelus) enable this boundary non-orthogonal correction by default for all physics.

Philip

randolph October 17, 2018 08:48

Quote:

Originally Posted by bigphil (Post 382173)
When you use fvc::snGrad it checks your fvScheme for what method to use. If it finds corrected then it will use non-orthogonal correction.


Each boundary patch can implement its own method to calculate the boundary snGrad so fvc::snGrad uses the values calculated by the boundary fvPatchField. So if you mesh contains fixedValue patches, then snGrad is given by (code taken from fvPatchField.C):
Code:

00176 // Return gradient at boundary
00177 template<class Type>
00178 Foam::tmp<Foam::Field<Type> > Foam::fvPatchField<Type>::snGrad() const
00179 {
00180    return (*this - patchInternalField())*patch_.deltaCoeffs();
00181 }

As can be seen, this assumes that the cell is orthogonal to the boundary.

Therefore if you are interested in orthogonal correction at the boundaries, you could implement a custom boundary condition where you define the snGrad as (taken from fixedDisplacementFvPatchVectorField.C found here):
Code:

115    const fvPatchField<tensor>& gradField =
 116        patch().lookupPatchField<volTensorField, tensor>
 117        (
 118            "grad(" +fieldName_ + ")"
 119        );
 120
 121    vectorField n = this->patch().nf();
 122    vectorField delta = this->patch().delta();
 123
 124    //- correction vector
 125    vectorField k = delta - n*(n&delta);
 126
 127    return
 128    (
 129        *this
 130      - (patchInternalField() + (k&gradField.patchInternalField()))
 131      )*this->patch().deltaCoeffs();

However, I believe non-orthogonal correction has been set to zero for a reason (for fluids anyway, solids need this correction).

Philip

Hi Philip,

Does Foam::fvPatchField<Type>::snGrad() only excuted when the fixedValue is used?

Here is my observation with fvPatchField<Type>::snGrad() and I do not exactly sure about what is the use of the fvPatchField<Type>::snGrad().

First, in the fixedValueFvPatchField.C, there is no fvPatchField<Type>::snGrad(). While, in the fixedGradientFvPatchField.H, fvPatchField<Type>::snGrad() return the gradient that you defined. Am I missing something?

Second, fvPatchField<Type>::snGrad() only referenced by wall functions and snGradScheme< Type >::snGrad().

Third, where does the solver need the fvPatchField<Type>::snGrad()? I thought the BC condition only impact the solution through the function valueInternalCoeffs, valueBoundaryCoeffs, gradientInternalCoeffs(), and gradientBoundaryCoeffs().

cnsidero October 17, 2018 09:13

Quote:

Originally Posted by bigphil (Post 710323)
In fact, as far as I know, some forks of OpenFOAM (e.g. Caelus) enable this boundary non-orthogonal correction by default for all physics.

It's not on by default. It can be enabled in the laplacianSchemes dictionary with the following syntax using, for example, the Laplacian of a scalar T:

Code:

laplacian(DT,T) Gauss linear secondOrderCorrected;
Basically use secondOrderCorrected as the snGrad scheme with the Laplacian term of interest. We performed a fairly exhaustive verification using method of manufactured solutions to prove it provides 2nd order accuracy on the boundaries. Refer to my talk from the Ann Arbour OF workshop:

https://sourceforge.net/projects/ope...t-OFW10-77.pdf

Note: With a fixed gradient BC it can recover 2nd order using only the least squares gradient reconstruction. Using the standard Gauss gradient reconstruction, 2nd order not possible because the boundary face value is unknown. We therefore implemented a corrected Gauss gradient, corrGauss, which iterates to improve the accuracy. The default is 2 iterations and improves the accuracy to somewhere between 1st and 2nd order.

-Chris

randolph October 17, 2018 21:24

Here are two papers for the future reference

A case-study in open-source CFD code verification, Part I: Convergence rate loss diagnosis

https://www.sciencedirect.com/scienc...78475417303774

A case-study in open-source CFD code verification. Part II: Boundary condition non-orthogonal correction

https://www.sciencedirect.com/scienc...78475417303762

bigphil October 21, 2018 13:51

Hi randolph,

See my replies below.

Quote:

Originally Posted by randolph (Post 710345)
Does Foam::fvPatchField<Type>::snGrad() only excuted when the fixedValue is used?

fvPatchField<Type>::snGrad() is executed for all derived boundary conditions classes that do not override it or explicitly call it. As you have seen, fixedGradient overrides the snGrad function, whereas fixedValue does not.

Quote:

Originally Posted by randolph (Post 710345)
Here is my observation with fvPatchField<Type>::snGrad() and I do not exactly sure about what is the use of the fvPatchField<Type>::snGrad().

First, in the fixedValueFvPatchField.C, there is no fvPatchField<Type>::snGrad(). While, in the fixedGradientFvPatchField.H, fvPatchField<Type>::snGrad() return the gradient that you defined. Am I missing something?

Both fixedValueFvPatchField.C and fixedGradientFvPatchField.H derive from fvPatchField, and the snGrad function is a virtual function. fixedGradient overrides the function because by definition fixedGradient "knows" the snGrad at the boundary i.e. the specified boundary gradient is the surface-normal gradient (snGrad); while fixedValue does not know the snGrad and so it does not override the snGrad function. I suggest you revise C++ virtual functions.

Quote:

Originally Posted by randolph (Post 710345)
Second, fvPatchField<Type>::snGrad() only referenced by wall functions and snGradScheme< Type >::snGrad().

It is used in other places as well: any time you need the boundary surface normal gradient e.g. when we call fvc::grad, we will need to calculate the gradient at the boundary, and the standard approach in OpenFOAM is to overwrite the snGrad at the boundary using the snGrad boundary condition function.

Quote:

Originally Posted by randolph (Post 710345)
Third, where does the solver need the fvPatchField<Type>::snGrad()? I thought the BC condition only impact the solution through the function valueInternalCoeffs, valueBoundaryCoeffs, gradientInternalCoeffs(), and gradientBoundaryCoeffs().

The solution value and gradient of the solution value can also affect the solution, particularly when the solution field boundary conditions are "corrected" after solving i.e. U.correctBoundaryConditions(): this will call the "evaluate()" function for all boundary conditions, which may in turn call snGrad, depending on the boundary condition.
Also, I said above, it will affect the calculation of the gradient field.

Hope it helps,
Philip

randolph October 21, 2018 14:22

Quote:

Originally Posted by bigphil (Post 711761)
Hi randolph,

See my replies below.



fvPatchField<Type>::snGrad() is executed for all derived boundary conditions classes that do not override it or explicitly call it. As you have seen, fixedGradient overrides the snGrad function, whereas fixedValue does not.



Both fixedValueFvPatchField.C and fixedGradientFvPatchField.H derive from fvPatchField, and the snGrad function is a virtual function. fixedGradient overrides the function because by definition fixedGradient "knows" the snGrad at the boundary i.e. the specified boundary gradient is the surface-normal gradient (snGrad); while fixedValue does not know the snGrad and so it does not override the snGrad function. I suggest you revise C++ virtual functions.


It is used in other places as well: any time you need the boundary surface normal gradient e.g. when we call fvc::grad, we will need to calculate the gradient at the boundary, and the standard approach in OpenFOAM is to overwrite the snGrad at the boundary using the snGrad boundary condition function.


The solution value and gradient of the solution value can also affect the solution, particularly when the solution field boundary conditions are "corrected" after solving i.e. U.correctBoundaryConditions(): this will call the "evaluate()" function for all boundary conditions, which may in turn call snGrad, depending on the boundary condition.
Also, I said above, it will affect the calculation of the gradient field.

Hope it helps,
Philip

Philip,

Thank you very much! It is much clear to me now!

Rdf

randolph October 23, 2018 10:33

Hi Philip,

I spend some time reading the implementation of the snGrad(). However, I have some trouble with understanding the calling sequence. For example, the fixed gradient, which is defined as:
Code:

           
//- Return gradient at boundary
            virtual tmp<Field<Type>> snGrad() const
            {
                return gradient_;
            }

But here is the calling diagram. I do not see the code where this function snGrad() call the other functions as shown in the diagram.

https://cpp.openfoam.org/v5/classFoa...4a9_cgraph.png

I am noob in both C++ and OpenFoam. I am very new to the handling of a unstrucured non-orthogonal grid. Could you please help me to understand the implementation of snGrad(). Particularly, how exactly the snGrad() work with other functions, such as valueInternalCoeffs(), valueBoundaryCoeffs(),gradientInternalCoeffs(), gradientBoundaryCoeffs(), to influent the solution.

Thanks,
Rdf


All times are GMT -4. The time now is 14:41.