fvm::ddtScheme in OpenFOAM

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….