fvm::ddt in OpenFOAM
Start from the deeper look into the laplacianFoam
solver. We are going to solve the:
1 2 3 4 5 6 7 8 9 10 11 12 13 while (simple.correctNonOrthogonal()){ fvScalarMatrix TEqn ( fvm::ddt(T) - fvm::laplacian(DT, T) == fvOptions(T) ); fvOptions.constrain(TEqn); TEqn.solve(); fvOptions.correct(T); }
In TEqn
, we have a term called fvm::ddt(T)
when the TEqn
object is constructing. We will have a deep look into this term. For fvm::ddt(T)
, function ddt
in fvmDdt.C
will be called:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 namespace fvm{ template <class Type >tmp <fvMatrix<Type>>ddt ( const GeometricField <Type, fvPatchField, volMesh>& vf ) { return fv::ddtScheme<Type>::New ( vf.mesh(), vf.mesh().ddtScheme("ddt(" + vf.name() + ')' ) ).ref().fvmDdt(vf); } ... }
Here the Type
will be determined by the type of vf
. It should be mentioned that ddt
is not a class but a function. In the return, The return object will call fv::ddtScheme<Type>::New
in ddtScheme.C
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <class Type > tmp <ddtScheme<Type>> ddtScheme <Type>: :New ( const fvMesh& mesh, Istream& schemeData ) { ... const word schemeName (schemeData) ; typename IstreamConstructorTable::iterator cstrIter = IstreamConstructorTablePtr_->find(schemeName); ... return cstrIter()(mesh, schemeData); }
as shown before, has a type of ```fvMesh```. The [```fvMesh.H```](https://cpp.openfoam.org/v7/fvMesh_8H.html) is defined as: 1 2 3 4 5 6 7 8 9 10 11 12 13 ```cpp class fvMesh : public polyMesh, public lduMesh, public surfaceInterpolation, public fvSchemes, public fvSolution, public data { ........ }
which is a subclass of fvSchemes
. In class fvSchemes
, there is a public access function called ddtScheme
:
1 ITstream& ddtScheme (const word& name) const ;
defined as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Foam::ITstream& Foam::fvSchemes::ddtScheme(const word& name) const { if (debug) { Info<< "Lookup ddtScheme for " << name << endl ; } if (ddtSchemes_.found(name) || defaultDdtScheme_.empty()) { return ddtSchemes_.lookup(name); } else { const_cast <ITstream&>(defaultDdtScheme_).rewind(); return const_cast <ITstream&>(defaultDdtScheme_); } }
The name
we put here will be "ddt(" + vf.name() + ')'
. E.g. we are solving the TEqn
, vf.name()
will be T
. Therefore, name
will be ddt(T)
here.
1 2 3 4 5 6 7 8 9 10 Foam::Istream& Foam::Istream::operator ()() const { if (!good()) { check("Istream::operator()" ); FatalIOError.exit (); } return const_cast <Istream&>(*this ); }
1 2 3 4 fileName objectPath () const { return path()/name(); }
ITstream
is a subclass of Istream
and tokenList
.:
1 2 3 4 5 6 7 class ITstream : public Istream, public tokenList { ...... }
, which is actually a ```List``` , is defined in [```tokenList.H```](https://cpp.openfoam.org/v7/tokenList_8H.html) as: 1 2 3 4 5 6 7 ```cpp namespace Foam { typedef List<token> tokenList; typedef List<token::tokenType> tokenTypeList; }
is a subclass of ```Ulist```: 1 2 3 4 5 6 7 8 9 ```cpp template<class T> class List : public UList<T> { ..... }
The ref()
is a function used to dereference the tmp
pointer, which will return the dereferenced pointer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <class T >inline T & Foam : :tmp<T>::ref() const { if (isTmp()) { if (!ptr_) { FatalErrorInFunction << typeName() << " deallocated" << abort (FatalError); } } else { FatalErrorInFunction << "Attempt to acquire non-const reference to const object" << " from a " << typeName() << abort (FatalError); } return *ptr_; }
to be continued….