SLGThermo class in OpenFOAM

SLGThermo class in OpenFOAM

The description of the SLGThermo class:

1
2
3
4
5
6
7
8
9
10
11
12
Description
Thermo package for (S)olids (L)iquids and (G)ases
Takes reference to thermo package, and provides:
- carrier : components of thermo - access to elemental properties
- liquids : liquid components - access to elemental properties
- solids : solid components - access to elemental properties

If thermo is not a multi-component thermo package, carrier is nullptr.
Similarly, if no liquids or solids are specified, their respective
pointers will also be nullptr.

Registered to the mesh so that it can be looked-up

In the coalChemistryFoam solver, a SLGThermo object is defined in createFields.H:

1
SLGThermo slgThermo(mesh, thermo);

The constructor of the SLGThermo is defined in SLGThermo.C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Foam::SLGThermo::SLGThermo(const fvMesh& mesh, fluidThermo& thermo)
:
regIOobject
(
IOobject
(
SLGThermo::typeName,
mesh.polyMesh::instance(),
mesh
)
),
thermo_(thermo),
carrier_(nullptr),
liquids_(nullptr),
solids_(nullptr)
{
Info<< "Creating component thermo properties:" << endl;

if (isA<basicSpecieMixture>(thermo))
{
basicSpecieMixture& mcThermo =
dynamic_cast<basicSpecieMixture&>(thermo);
carrier_ = &mcThermo;

Info<< " multi-component carrier - " << mcThermo.species().size()
<< " species" << endl;
}
else
{
Info<< " single component carrier" << endl;
}

if (thermo.found("liquids"))
{
liquids_ = liquidMixtureProperties::New(thermo.subDict("liquids"));
Info<< " liquids - " << liquids_->components().size()
<< " components" << endl;
}
else
{
Info<< " no liquid components" << endl;
}

if (thermo.found("solids"))
{
solids_ = solidMixtureProperties::New(thermo.subDict("solids"));
Info<< " solids - " << solids_->components().size()
<< " components" << endl;
}
else
{
Info<< " no solid components" << endl;
}
}

The definition of the three phases objects:

1
2
3
4
5
6
7
8
//- Reference to the multi-component carrier phase thermo
basicSpecieMixture* carrier_;

//- Additional liquid properties data
autoPtr<liquidMixtureProperties> liquids_;

//- Additional solid properties data
autoPtr<solidMixtureProperties> solids_;

The definition of thermo object in the parameter list:

1
2
autoPtr<psiReactionThermo> pThermo(psiReactionThermo::New(mesh));
psiReactionThermo& thermo = pThermo();

The detailed initialization of the pThermo object was talked before in the discussion of the psiReactionThermo class. The initialization of the properties of each phases is done in the constructor of the SLGThermo . The gas phase which is called carrier here is initialized by a dynamic_cast. As for the initialization of the liquid and solid phase, the mechanisms are the same. I will pick the initialization of the solid phase here as an example. Here I separate the code from the constructor:

1
2
3
4
5
6
7
8
9
10
if (thermo.found("solids"))
{
solids_ = solidMixtureProperties::New(thermo.subDict("solids"));
Info<< " solids - " << solids_->components().size()
<< " components" << endl;
}
else
{
Info<< " no solid components" << endl;
}

The thermo object here is a dict that we initialize before. In the tutorial simplifiedSiwek, this dict will be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
thermoType
{
type hePsiThermo;
mixture reactingMixture;
transport sutherland;
thermo janaf;
energy sensibleEnthalpy;
equationOfState perfectGas;
specie specie;
}
chemistryReader foamChemistryReader;
foamChemistryThermoFile "$FOAM_CASE/constant/foam.dat";
foamChemistryFile "$FOAM_CASE/constant/foam.inp";
inertSpecie N2;
liquids
{
H2O ;
}
solids
{
C
{
rho 2010;
Cp 710;
kappa 0.04;
Hf 0;
emissivity 1;
}
ash ;
}
}
will be true in this case. Then we call ```solidMixtureProperties::New```:
1
2
3
4
5
6
7
8
9
10
11
12

```cpp
Foam::autoPtr<Foam::solidMixtureProperties> Foam::solidMixtureProperties::New
(
const dictionary& thermophysicalProperties
)
{
return autoPtr<solidMixtureProperties>
(
new solidMixtureProperties(thermophysicalProperties)
);
}

This will call the constructor of the solidMixtureProperties class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Foam::solidMixtureProperties::solidMixtureProperties(const dictionary& dict)
:
components_(),
properties_()
{
components_ = dict.toc();
properties_.setSize(components_.size());

forAll(components_, i)
{
if (dict.isDict(components_[i]))
{
properties_.set
(
i,
solidProperties::New(dict.subDict(components_[i]))
);
}
else
{
properties_.set
(
i,
solidProperties::New(components_[i])
);
}
}
}

The components_ and properties_ are defined as:

1
2
3
4
5
//- The names of the solids
List<word> components_;

//- The solidProperties properties
PtrList<solidProperties> properties_;

The input dict here will be thermo.subDict("solids"), which in this tutorial:

1
2
3
4
5
6
7
8
9
10
11
{
C
{
rho 2010;
Cp 710;
kappa 0.04;
Hf 0;
emissivity 1;
}
ash ;
}

Here the components will have 2 elements. dict.isDict(components_[i]) will check if a subdict exists or not. For C, the subdict exists and for ash it doesn’t.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Foam::autoPtr<Foam::solidProperties> Foam::solidProperties::New
(
const dictionary& dict
)
{
......

const word solidType(dict.dictName());

if (dict.found("defaultCoeffs"))
{
......
}
else
{
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(solidType);

if (cstrIter == dictionaryConstructorTablePtr_->end())
{
FatalErrorInFunction
.....
}

return autoPtr<solidProperties>(cstrIter()(dict));
}
}

As the first component is C, this will call the constructor of C in C.C

1
2
3
4
5
6
7
8
9
10
11
Foam::C::C()
:
solidProperties(2010, 710, 0.04, 0.0, 1.0)
{
if (debug)
{
WarningInFunction
<< "Properties of graphite need to be checked!!!"
<< endl;
}
}

As C is inherited from class solidProperties, it then initialized the constructor of solidProperties which is defined in solidProperties.C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Foam::solidProperties::solidProperties
(
scalar rho,
scalar Cp,
scalar kappa,
scalar Hf,
scalar emissivity
)
:
rho_(rho),
Cp_(Cp),
kappa_(kappa),
Hf_(Hf),
emissivity_(emissivity)
{}

For ash, it does not have any subdict. It will call the following New function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Foam::autoPtr<Foam::solidProperties> Foam::solidProperties::New
(
const word& name
)
{
......

ConstructorTable::iterator cstrIter = ConstructorTablePtr_->find(name);

if (cstrIter == ConstructorTablePtr_->end())
{
FatalErrorInFunction
......
}

return autoPtr<solidProperties>(cstrIter()());
}

This will then call the constructor of ash defined in ash.C:

1
2
3
4
5
6
7
8
9
10
11
Foam::ash::ash()
:
solidProperties(2010, 710, 0.04, 0.0, 1.0)
{
if (debug)
{
WarningInFunction
<< "Properties of ash need to be checked!!!"
<< endl;
}
}

And this will also call the solidProperties constructor as what we have explained before.