fvMatrix, fvOptions and SuSp: automatic implicit/explicit source-term treatment
fvMatrix, fvOptions and SuSp: automatic implicit/explicit source-term treatment to facilitate the matrix diagonal dominance
The matrix equation to be solved in scalarTransportFoam reads: Code:
//“scalarTransportFoam.C” The object fvOptions on the right hand side is of IOoptionList type (which is derived from optionList). The class IOoptionList was designed to facilitate the addition of source terms to the matrix equation. It can handle multiple sources of different nature in a systematic way. fvOptions(T) expands into Code:
//”fvOptionListTemplates.C” Code:
70 source.addSup(mtx, fieldI); So, initial equation Code:
fvm::ddt(T) Code:
fvMatrix_A == fvMatrix_B Code:
//”fvMatrix.C” Code:
//”fvMatrix.C” Code:
//”fvMatrix.C” Code:
1065 lduMatrix::operator-=(fvmv); Code:
//"lduMatrixOperations.C" Code:
1066 source_ -= fvmv.source_; Code:
fvMatrix_A == fvMatrix_B fvMatrix_C = fvMatrix_A - fvMatrix_B where (in pseudocode): Code:
C.diag() = A.diag() - B.diag(); Code:
//” SemiImplicitSource.C” Code:
//"system/fvOptions" Code:
eqn += Su + fvm::SuSp(Sp, psi); Code:
eqn += fvm::SuSp(Sp, psi); Code:
// ”fvMatrix.C” Code:
eqn.diag() += (fvm::SuSp(Sp, psi)).diag(); Code:
// ”fvmSup.C” Code:
210 fvm.diag() += mesh.V()*max(susp.field(), scalar(0)); Code:
212 fvm.source() -= mesh.V()*min(susp.field(), scalar(0)) Code:
{ Code:
tmC().diag() = tmA.diag() - tmOL.diag(); Code:
tmC().diag() = tmA.diag() - mesh.V()*Sp.field(); Is it a bug? If it is not, can anyone tell me where I went wrong in my reasoning? (Kind of) solution The problem comes from the fact that the initial equation is formulated in the form: Code:
fvMatrix_A == fvOptions(T); Code:
fvMatrix_A == SuSp(Sp, T); Code:
fvMatrix_C.diag() = fvMatrix_A.diag() - mesh.V()*Sp.field; Code:
fvMatrix_A == fvOptions(T); Code:
fvMatrix_A == SuSp(Sp, T); Code:
fvMatrix_A - SuSp(Sp, T) == 0; Code:
fvMatrix_A + SuSp(-Sp, T) == 0; Code:
fvMatrix_C.source() = Code:
fvMatrix_C.source() = Code:
fvMatrix_A + SuSp(-Sp, T) == 0; The problem is that solvers in OpenFOAM are designed so that fvOptions is on the rhs which looks quite reasonable from the math base: Code:
fvMatrix_A == fvOptions(T); Thanks. |
The final part of the previous post (called "(Kind of) solution") was incorrect and should be ignored. The info presented below is what should have actually went in place of that wrong part.
(Kind of) solution The problem comes from the fact that the choice between implicit/explicit formulation of a source term SuSp(Sp, T) depends not only on the Sp being positive/negative but also on the way this source term interacts with other terms in the matrix equation. For example, Code:
1) fvMatrix_A + SuSp(Sp, T); Code:
2) fvMatrix_A - SuSp(Sp, T); The second expression should be rewritten by bringing the sign “-“ into the brackets (i.e. effectively, multiplying Sp by -1: SuSp(-Sp, T)) : Code:
2) fvMatrix_A + SuSp(-Sp, T); Most matrix equations in OpenFOAM's solvers look like: Code:
fvMatrix_A == fvOptions(T); Code:
fvMatrix_A == SuSp(Sp, T); Code:
fvMatrix_A == -SuSp(-Sp, T); Code:
// ”SemiImplicitSource.C” Code:
// ”SemiImplicitSource.C” P.S. I believe something like lazy evaluation technique can also solve this sort of problems. In which case the actual calculation of a final fvMatrix can be deffered until the very last operation in the series of matrix operations. Unfortunately, within a frame of current OpenFOAM implementation this is not yet posible. |
Thanks a lot!
Today I also came across this issue and was really hoping for some solution. You have nicely describe the problem. Any solution or explanation you found? If not I will also put a problem from solidificationMeltingSource.C where it calculated Sp (sink) term for velocity, and I have found that eqn.Sp() is negative at the time when it should provide sink to the velocity equation. Regards gtarang |
Solution is given in my second post:
Quote:
Quote:
Quote:
|
Hi Sergei,
Thank you for your brilliant post! I'm relatively new to working with OF source code and I didn't expect to find such kind of issues in my own code. Basically I hard-coded a semi-implicit temperature source in my incompressible solver. Everything worked fine until I tried to achieve the same result using fvOptions and scalarSemiImplicitSource. I struggled for several days, with my solver was repeatedly exploding. Then I recalled having found this thread and I tried to change the sign to both the fvOptions term in TEqn and the Su/Sp coefficients in the fvOptions dictionary file. Magically, now everything works just fine as before. It is quite annoying indeed. As I understand the solution is either to change that single line in semiImplicitSource.C (which is the most correct approach I think, but quite overkill IMHO since I should compile my own version of the template class) or, as I did, change signs in the specific equation and in the corresponding dictionary file (but I admit it is ugly, inconsistent with other equations and would behave badly if other kinds of fvOptions are added to the same equation, I believe). Another solution could be maybe to replace fvm::SuSp() with fvm::Sp() which should enforce implicit treatment in all cases, if I got it right. I didn't try yet, though. Anyway, I acknowledge that after some reasoning one can recognize and solve this issue, but I believe that one must have at least some experience with the source code to find out, understand and correct it. If fvOptions are intended to provide all users (more basic ones included) with some run-time tool to add simple sources to equations (with semiImplicitSource being the simplest and most common one), I believe that such behaviour can be regarded as a bug. Basically, if you try to use it as explained in the official documentation things won't simply work in many cases with no apparent reason and no possibility of solution without touching the source code. Did you try to file some kind of official issue report about this? Andrea |
Hi Andrea.
No, I haven't submitted any bug report on this issue. I believe that the most correct, consistent and robust way to overcome it is to build your own version of SemiImplicitSource class with its function addSup being modified: Code:
// ”SemiImplicitSource.C” |
2 Attachment(s)
Hi everyone!
I tried the fvOptions with scalarCodedSource to link a source term on epsilon to the k-e turbulence model for 1D (x=1mm, y=150mm, z=1mm) ABL simulation and it seem that I got similar issue. If you got time and knowledge, It would be appreciated to know your insight/suggestion/tips about the code I did? By the results, the calculation by the formula are good since I printed out the results in a text file and verified the validity but the source term doesn't seem to be applied to the domain(see picture). The boundary wall seem to work (because in the epsilon patch I choose the BC "epsilonWallFunction") and then after, the values are null. The simulation stop after 11 step of iteration... Thank again for your comment and your help. Best Regards, Code:
/*--------------------------------*- C++ -*----------------------------------*\ |
I made a small test case to see the effects of the source term to fvMatrix. In my case (heat conduction, basically laplacian solver) since diag() is negative, the following equation(given in the last line) increases the diagonal dominance, not deteriorating it.
I feel mostly diag() will be having -ve entries and the original implementation can be retained, isn't it? tmC().diag() = tmA.diag() - mesh.V()*Sp.field(); |
All times are GMT -4. The time now is 00:05. |