Professional Documents
Culture Documents
Implementation of quasi-2D
magnetohydrodynamic mixed convection
solver for incompressible flows in liquid
metal channels
Disclaimer: This is a student project work, done as part of a course where OpenFOAM and some
other OpenSource software are introduced to the students. Any reader should be aware that it
might not be free of errors. Still, it might be useful for someone who would like to learn some
details similar to the ones presented in the report and in the accompanying files. The material has
gone through a review process. The role of the reviewer is to go through the tutorial and make
sure that it works, that it is possible to follow, and to some extent correct the writing. The
reviewer has no responsibility for the contents.
The main requirements of a tutorial in the course is that it should teach the four points: How to
use it, The theory of it, How it is implemented, and How to modify it. Therefore the list of learning
outcomes is organized with those headers.
What is the assumption underlying the coupling of energy and momentum equations in a
boussinesqBuoyant-like solver.
The basic physics of magnetohydrodynamics to understand mhdFoam.
How it is implemented:
How the equations of boussinesqBuoyantFoam and mhdFoam are implemented in the respective
solvers.
How to modify it:
It will be shown how to modify an existing solver like boussinesqBuoyantFoam to get a new
solver called Q2DmhdFoam that solves a magnetohydrodynamic problem with buoyancy. For
that, the simplification of Sommeria and Moreau [1] will be used and it will be explained why
it is useful to use this solver to run magnetohydrodynamic cases in a faster way. Also, the
difference of this approach with respect to the existing mhdFoam will be shown.
Furthermore, it will be shown how to write a script to automate the pre-processing and post-
processing and why this is useful, for example, for creating meshes in magnetohydrodynamics
since the approximate depth of the boundary layers in them can be known a priori. Due
to steep gradients in the boundary layers, it is necessary to take care of the mesh to obtain
acceptable results.
The Q2DmhdFoam solver will be made available.
1
Prerequisites
The reader is expected to know the following in order to get maximum benefit out of this report:
Basic object-oriented programming knowledge.
2
Contents
1 Introduction 5
2 Background 6
2.1 Magnetohydrodynamics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.1 The coupling of momentum and electromagnetic equations . . . . . . . . . . 6
2.1.2 Low magnetic Reynolds approximation . . . . . . . . . . . . . . . . . . . . . . 7
2.2 The Boussinesq approximation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 The Energy equation and the source term . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Complete MHD equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Dimensionless numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.6 Characteristic MHD flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.7 Quasi-2D magnetohydrodynamic flow . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3 Existing solvers 12
3.1 The mhdFoam solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.1.1 Implementation of mhdFoam . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.1.2 Using the hartmann tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 The boussinesqBuoyantFoam solver . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1 Implementation of boussinesqBuoyantFoam . . . . . . . . . . . . . . . . . . 20
3.2.2 Using the heatedCavity tutorial . . . . . . . . . . . . . . . . . . . . . . . . . 20
A Developed codes 53
A.1 Q2DmhdFoam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
A.2 Python script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3
Nomenclature
Acronyms
MHD Magnetohydrodynamics
English symbols
B Magnetic field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . T
E Electric field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . N/C
fm Magnetic force per unit volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . N/m3
j Electric current density . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A/m2
v Fluid velocity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m/s
q̇ Heat deposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . W/m3
m Exponential shape parameter
p Pressure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pa
W Dimensionless velocity
Greek symbols
β Thermal expansion coefficient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1/°C
µm Fluid magnetic permeability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . T · m/A
ν Fluid kinematic viscosity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m2 /s
ρ Fluid density . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kg/m3
ρc Charge density . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C/m3
σ Fluid electrical conductivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1/(Ωm)
τHa Hartmann braking time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . s
θ Dimensionless temperature
εm Fluid permitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C2 /(Nm2 )
Subscripts
c Cold
h Hot
o Reference value (for the Boussinesq approximation)
4
Chapter 1
Introduction
This chapter is devoted to an overview of what the reader should expect from this report.
The goal of this document is to show how to implement a simplified magnetohydrodynamic
solver in foam-extend. This will not be done from scratch, but taking advantage of the other
existing solvers with shared features related to the intended objective.
Magnetohydrodynamics (MHD) is a complex field of physics derived from fluid mechanics and
electromagnetism. It is necessary to analyze it when studying the flow of a conducting material
immersed in a magnetic field. This is especially interesting in nuclear fusion, where the plasma
exists and where liquid metal flows can be used with three purposes: to breed the fuel for fusion
(tritium), to be used as a coolant to collect heat energy for electricity generation and for shielding
of the components outside the reactor. An example of liquid breeding blanket for fusion is the Dual
Coolant Lithium Lead (DCLL) [2].
For studying MHD, the need of coupling temperature, velocity and electromagnetic fields makes
the solution hard to converge and requires a large amount of computational time. Sommeria and
Moreau [1] showed a simpler perspective of MHD flows that takes into account buoyancy (tem-
perature coupled with velocity) in the solution of MHD flows. This two-dimensional simplification
approach allows simulating several MHD cases to obtain preliminary results without the pain of
going through large simulation times with more rigorous models. Therefore, the report focuses on
this approach.
To this aim, the second chapter will expose the theoretical fundamentals for understanding mag-
netohydrodynamics and buoyancy hypothesis in incompressible flows. The third chapter will then
help the reader to understand and to use the solvers already existing in the foam-extend 4.1 NR
distribution that relate to the mentioned topics. The fourth chapter shows how to implement the
Q2DmhdFoam solver and its basic usage. Finally, the fifth chapter presents a Python script developed
to use for the validation of the new solver, also considering meshing particularities in magnetohy-
drodynamic flows.
The accompanying files serve as a starting point to follow the procedures described in the docu-
ment. The files can also be found in GitHub: https://github.com/iraola/Q2DmhdFoam.
5
Chapter 2
Background
2.1 Magnetohydrodynamics
This section presents the basics of magnetohydrodynamics for later understanding its CFD imple-
mentation.
6
2.1. Magnetohydrodynamics Chapter 2. Background
∇·j =0 (2.6)
j = σ(E + v × B) (2.7)
7
2.2. The Boussinesq approximation Chapter 2. Background
βg(T − To ) (2.12)
where g the acceleration of gravity vector. Therefore, the momentum equation coupled with the
temperature has the form of
∂v ∇p µ
+ (v · ∇)v = − + ∇2 v + βg(T − To ) (2.13)
∂t ρo ρo
This expression is valid for incompressible flows. k is the thermal conductivity and cp is the specific
heat of the fluid
The causes of temperature gradients in liquid metal channels are typically modeled as an expo-
nential function in fusion research such as in the works of Vechta et al. [6] and Urgorri et al. [2]
with the term y
q̇ = qo e−( a +1)m (2.15)
that can be added to Eq. (2.14) as a source term to account for the external influence of neutron
deposition in the temperature field of the fluid. y stands for the position in the direction of the
heat deposition—greater as we get close to the core—, a stands for the half length of the channel
in that direction, m stands for the exponential shape parameter and qo stands for the value of the
volumetric heat deposition in the position y = −a.
∇·v =0 (2.16a)
B2
∂v ∇p 2 1
+ (v · ∇)v = − + ν∇ v + −∇ + (B · ∇)B + βg(T − To ) (2.16b)
∂t ρ µm ρ 2
∇·B =0 (2.16c)
∂B
= ∇ × (v × B) + η∇2 B (2.16d)
∂t
∂T k 2 y
+ (v · ∇)T = ∇ T + qo e−( a +1)m (2.16e)
∂t ρcp
8
2.5. Dimensionless numbers Chapter 2. Background
gβ∆T a3
Gr = (2.19)
ν2
where ∆T is the characteristic temperature difference and a is the characteristic length in the
direction of heat flux (perpendicular to the magnetic and velocity field), which corresponds to half
the distance between walls in this direction. It is also important to recall from the previous section
the importance of the thermal expansion coefficient of the fluid, β, in the buoyancy forces and,
therefore, in the numerical solution of temperature-based solvers.
Besides these three numbers, it is interesting to include here an important quantity regarding time
step constrains in a computational fluid dynamics tool such as the Courant number, Co, calculated
as
v∆t
Co = (2.20)
∆x
where, ∆t is the calculation time step, v is the velocity of the fluid and ∆x is the cell size in
the direction of the velocity with respect to a cell in a computational fluid dynamics mesh. In
simulation, a limit to the Courant number is often established to ensure temporal accuracy and
numerical stability. A typical limit to avoid instability in explicit-scheme solvers is Co < 1 [3]. This
means that, upon each iteration, the solver calculates a new time step that fulfills that the maximum
Courant number in the domain does not overcome this value.
9
2.6. Characteristic MHD flow Chapter 2. Background
Hartmann wall
δHa
Side wall
2b
δside
δw Hartmann wall
2a
Figure 2.1: Cross section of an MHD square duct and its elements of interest.
Under the circumstance of a pressure-driven flow in a duct such as this, an electric current
density, j, is induced in the core flow along the y direction following Ampère’s law as shown in
section 2.1.1.
Besides, and because of the present magnetic field, the Lorentz force (Eq. (2.8)) is generated in
the negative direction of x, that is to say, the other way around that the pressure drop that pushes
the flow forward. This causes the characteristic flattened core flow in MHD as it can be seen in
Figure 2.2 (right). As the Hartmann number increases, this damping effect also increases.
Figure 2.2: Streamlines of the electric current in A/s·m2 (left) and characteristic velocity profile in
m/s (right) of a MHD case with insulating walls.
When walls are perfectly insulating, most of the electric current close to the side walls is parallel
to the magnetic field (see Figure 2.2, left). This occurs because of charge conservation, so electric
current streamlines are forced to close their path inside the fluid domain. As this happens, little
damping is generated by the Lorentz force close to side √walls and only viscous forces take place. The
side boundary layers δside develop proportionally to 1/ Ha. We will not consider conducting walls
since all cases developed in this report involve insulating walls.
On the other hand, Lorentz force exists close to Hartmann walls, but in the positive direction of
the the flow since the electric current goes in the opposite direction to the bulk in that boundary,
favoring flow in those regions. As a result, the depth of the Hartmann boundary layers is always
thinner than side boundary layers and decreases according to δHa ∝ 1/Ha.
10
2.7. Quasi-2D magnetohydrodynamic flow Chapter 2. Background
11
Chapter 3
Existing solvers
In this chapter, we will review the mhdFoam and boussinesqBuoyantFoam solvers. These are rela-
tively simple solvers consisting of the minimum set of files that most of the OpenFOAM solvers have:
the main file with the name of the solver, the createFields.H file, which creates the objects that
the solver will use to contain the fields, the readTransportProperties file, which takes care of
reading the user input properties, and the files and options files, which define the name of the
solver and other files needed to compile it. We will focus on the main files since the physical theory
explained in Chapter 2 can be found in terms of the solved equations.
solve(UEqn == -fvc::grad(p));
Here, phiB is the analogous of the surface flux phi for the magnetic field and DBU is a constant
calculated in the createFields.H file as1
1
DBU = (3.1)
2µm ρ
1 The magnetic permeability µm should not be mistaken with the dynamic viscosity of the fluid, µ. In mhdFoam,
the kinematic viscosity ν is used instead of µ and therefore the magnetic permeability is called just mu.
12
3.1. The mhdFoam solver Chapter 3. Existing solvers
The PISO algorithm is then used to satisfy mass conservation alongside with Eq. (2.9). This
document does not cover the PISO algorithm: it will just be used as implemented in the existing
solvers.
After this, the so-called B-PISO loop is executed in which the magnetic Eq. (2.10) is solved. The
piece of code that states this equation is shown next.
Implementation of the magnetic field equation for mhdFoam in the mhdFoam.C file.
fvVectorMatrix BEqn
(
fvm::ddt(B)
+ fvm::div(phi, B)
- fvc::div(phiB, U)
- fvm::laplacian(DB, B)
);
BEqn.solve();
Here, the curl term in Eq. (2.10) is expanded into the (B · ∇)v and (v · ∇)B terms to fit
the OpenFOAM div operator (note that there would be two other terms in this expansion that are
removed taking into account that ∇ · B = 0 and ∇ · v = 0). DB is a constant that represents a
magnetic diffusivity and is calculated in createFields.H in terms of the electric conductivity and
the magnetic permeability as
1
DB = (3.2)
σµm
13
3.1. The mhdFoam solver Chapter 3. Existing solvers
initially of uniformly zero value, will develop with the simulation. A no-slip condition is set at the
walls using a zero fixedValue boundary. The hydrodynamic and magnetic pressures, p and pB can
be left as default.
The mesh defined in the blockMeshDict file is made of 100 cells in the flow direction and 40
cells in the perpendicular direction, making this a two-dimensional case in the x-y direction. The
mesh in this direction must be sufficiently fine to be able to represent the steep gradients in an MHD
boundary layer. The difference between this setup and the 2D approach shown in Chapter 2 is that,
in the hartmann case, the magnetic field goes along the y axis. Therefore, the domain represents
the flow between the two Hartmann walls.
To visualize the mesh we will copy the tutorial in our run directory (after sourcing our FOAM
distribution).
cd $FOAM_RUN
cp -r $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann .
cd hartmann
and we will perform the blockMesh command. The generated mesh is shown in Figure 3.1 using
paraview.
Hartmann wall
Velocity
14
3.1. The mhdFoam solver Chapter 3. Existing solvers
Figure 3.2: Velocity profile extracted from the hartmann tutorial using paraview.
Modified constant/polyMesh/blockMeshDict file for the hartmann3D case. Added code in red.
convertToMeters 1;
vertices
(
(0 -1 -1)
(20 -1 -1)
(20 1 -1)
(0 1 -1)
(0 -1 1)
(20 -1 1)
(20 1 1)
(0 1 1)
);
blocks
(
hex (0 1 2 3 4 5 6 7) (100 40 40) simpleGrading (1 1 1)
);
15
3.1. The mhdFoam solver Chapter 3. Existing solvers
Modified constant/polyMesh/blockMeshDict file for the hartmann3D case (cont.). Added code in
red.
edges
(
);
boundary
(
...
frontAndBack
{
type patch;
faces
(
(0 3 2 1)
(4 5 6 7)
);
}
);
mergePatchPairs
(
);
// ************************************************************************* //
wall
Side
ll
n wa
an
artm
H
Velocity
Magnetic Field
16
3.1. The mhdFoam solver Chapter 3. Existing solvers
Secondly, we need to modify the boundary conditions in the different initial fields where the
boundary type empty stood before and copy the boundary conditions of the other walls. For the
magnetic field, it is needed to impose a fixed value boundary. We also change the direction of the
magnetic field to the z axis in agreement with the geometry shown in Chapter 2.
Modified magnetic field file (0/B) for the hartmann3D case. Modified code in red.
boundaryField
{
...
frontAndBack
{
type fixedValue;
value uniform (0 0 20);
}
}
Modified frontAndBack velocity boundary condition (0/U) for the hartmann3D case.
boundaryField
{
...
frontAndBack
{
type fixedValue;
value uniform (0 0 0);
}
}
Modified frontAndBack pressure boundary condition (0/p and 0/pB) for the hartmann3D case.
boundaryField
{
...
frontAndBack
{
type zeroGradient;
}
}
We will also modify the contents of the system/sampleDict file to produce the raw data for
plotting the two velocity profiles that will be shown in Figure 3.4, representative of the side and
Hartmann boundary layers. Once the case is run, the post-process can be called using the command
sample and it will generate data files under a new postProcessing directory. The new file shall
look as follows:
17
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
);
surfaceFormat null;
surfaces
();
fields
(
U
);
// ************************************************************************* //
After these changes, the case can be meshed and run. Being a 3D case solving coupled velocity
and magnetic fields, the case can now take several minutes.
blockMesh
mhdFoam
sample
The results of the two perpendicular velocity profiles are shown in Figure 3.4. It can be seen
how the gradients in the direction of the magnetic field, i.e. along the Hartmann boundary layers,
are much steeper than in the side boundary layers.
18
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
Figure 3.4: Comparison of side and Hartmann boundary layers (y and z directions, respectively).
Generated in paraview.
solvers
heatTransfer
boussinesqBuoyantFoam
buoyantBoussinesqPisoFoam
buoyantBoussinesqSimpleFoam
buoyantPisoFoam
buoyantSimpleFoam
buoyantSimpleRadiationFoam
chtMultiRegionFoam
chtMultiRegionSimpleFoam
For clarification and to give the user a quick access guide, the main purpose of each of them will
be summarized below (the multiRegion solvers will not be considered):
buoyantPisoFoam. Transient solver for buoyant, turbulent flow of compressible fluids. It uses
the PISO algorithm.
buoyantSimpleFoam. Steady-state solver for buoyant, turbulent flow of compressible fluids. It
uses the SIMPLE algorithm.
19
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
solve(UEqn == -fvc::grad(p));
Then, the solver uses the PISO algorithm to accommodate for mass conservation, similarly to
the mhdFoam solver previously seen. After this, the energy equation is solved and the density, which
exists as a scalar field, giving different values to each cell depending on the local temperature, is
recalculated with the resulting temperature. The actual code that performs this task is shown next,
also extracted from the boussinesqBuoyantFoam.C file.
20
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
fvSchemes
fvSolution
sampleDict
The main difference with respect to the mhdFoam tutorial is, as it could be expected, the presence
of the temperature field and the g file that contains the value of the acceleration of gravity for
buoyancy purposes. The mesh defined in the blockMeshDict file represents the typical cavity
geometry used in tutorials. If generated with the blockMesh command, the mesh can be visualized
with paraview as shown in Figure 3.5.
The cavity cases are two-dimensional (the front and back faces of the geometry are defined as
empty) and the rest of boundaries are defined as walls. Specifically, the heatedCavity case defines
the velocity field (0/U) so that all walls are static and with no-slip condition:
21
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
The temperature file (0/T) states the internal initial fluid temperature and left wall temperature
as 273 K but also sets the right wall temperature constant at 373 K:
This will create a temperature gradient that, together with the Boussinesq model that will change
the density of the fluid in different places of the domain and the definition of the gravity downwards
in the negative y direction (shown next), will start a convective movement of the fluid.
22
3.2. The boussinesqBuoyantFoam solver Chapter 3. Existing solvers
dimensions [0 1 -2 0 0 0 0];
value ( 0 -9.81 0 );
// ************************************************************************* //
If we run the boussinesqBuoyantFoam solver, we can see this effect as shown in Figure 3.6 in
a snapshot of the time step 4, where the perturbation of the right wall temperature is starting and
thus the higher velocities are in the right side of the domain.
Figure 3.6: Arrows representing the magnitude and direction of the velocity field in the
heatedCavity domain. The image was extracted using paraview and sequentially applying the
Cell Centers and Glyph filters.
23
Chapter 4
In this chapter, it will be shown how the new solver Q2DmhdFoam is implemented step by step, starting
from a copy of the boussinesqBuoyantFoam available in the foam-extend 4.1 NR distribution, and
some examples of the use of it.
Q2DmhdFoam uses the quasi-two-dimensional approach explained in Chapter 2. Therefore, it is a
simplified solver, thus has a limited scope of use, i.e. it is less general than the mhdFoam solver but
it accounts for the analysis of buoyant effects, where mhdFoam does not, with a low computing cost.
Specifically, the scope of the Q2DmhdFoam reduces to:
It applies only to 2D simulations. 3D simulations may have no physical meaning since the set
of equations is reduced to two dimensions.
The results are only valid for a certain direction of the magnetic field. The magnetic field is
input by the user as a scalar field because the solver assumes that field to be perpendicular to
the Hartmann layers. Therefore the user must configure the geometry of the case in accordance
with this assumption.
For the heat deposition to work properly, the channel must be centered in the 0 position
(whether in the X, Y or Z direction). The user is free to specify the axis along which the heat
deposition takes place with the coord variable in the case files.
foam
cp -r --parents applications/solvers/heatTransfer/boussinesqBuoyantFoam \
$WM_PROJECT_USER_DIR
cd $WM_PROJECT_USER_DIR
Note that we use the --parents flag in order to keep the same directory structure as in
the main installation. Now, we see that we have created an applications directory with the
solvers/heatTransfer/boussinesqBuoyantFoam path inside if they didn’t exist before.
Now we will rename the new files in order to avoid conflict with the pre-existing files and to give
an identity to the new solver. We will call it Q2DmhdFoam. Also, we will change the name of the
family of solvers in which this solver is located, i.e. from heatTransfer to electromagnetics.
cd applications/solvers
mv heatTransfer electromagnetics
24
4.1. Implementation of the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
cd electromagnetics
mv boussinesqBuoyantFoam Q2DmhdFoam
cd Q2DmhdFoam
Before checking our files, we should perform wclean to avoid looking into temporary inter-
mediate files. After this, there is a file named after the name of the base solver, the main file
boussinesqBuoyantFoam. We need to change it.
mv boussinesqBuoyantFoam.C Q2DmhdFoam.C
The name boussinesqBouyantFoam still appears written inside several files in the current direc-
tory, as it can be seen by executing the grep command:
grep -r boussinesqBuoyantFoam
Make/files:boussinesqBuoyantFoam.C
Make/files:EXE = $(FOAM_APPBIN)/boussinesqBuoyantFoam
Q2DmhdFoam.C: boussinesqBuoyantFoam
including the Make/files file, which will contain the actual name under which the solver is compiled.
We solve this using the sed command.
At this point, we should have a functional solver named Q2DmhdFoam that has the same func-
tionality as boussinesqBuoyantFoam solver. This can be checked by compiling the solver (located
at the solver directory):
wmake
Also, a good practice is running the heatedCavity tutorial with the new Q2DmhdFoam solver and
check that everything works properly.
The first thing we now do is checking the Q2DmhdFoam.C file. We see that the old description is
still written:
Application
Q2DmhdFoam
Description
Transient solver for buoyancy-driven laminar flow of incompressible
Newtonian fluids using the Boussinesq Model
\*---------------------------------------------------------------------------*/
We will change this so a new user can understand better what the new solver will do, so we
change the Description part by the following.
25
4.1. Implementation of the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
\*---------------------------------------------------------------------------*/
Modifying readTransportProperties.H
Before going deeper into the main Q2DmhdFoam.C file, we want to define the new parameters that
the user will need to provide, since the boussinesqBuoyantFoam solver was not prepared for elec-
tromagnetic properties. Typically, the parameters input by the user in the transportProperties
file are read by the solver in the createFields.H file. In foam-extend, this file usually includes
the code that reads the transport properties in readTransportProperties.H. We will take a look
at this file:
IOdictionary transportProperties
(
IOobject
(
"transportProperties",
runTime.constant(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
dimensionedScalar rho0
(
transportProperties.lookup("rho0")
);
dimensionedScalar T0
(
transportProperties.lookup("T0")
);
dimensionedScalar nu
(
dimensionedScalar(transportProperties.lookup("mu"))/rho0
);
dimensionedScalar DT
(
dimensionedScalar(transportProperties.lookup("k"))/
(rho0*dimensionedScalar(transportProperties.lookup("Cp")))
);
dimensionedScalar beta
(
transportProperties.lookup("beta")
);
We will keep this code since we want our solver to deal with buoyant forces. The only exception is
the code part that gets the kinematic viscosity nu. Here it is calculated using the dynamic viscosity
26
4.1. Implementation of the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
mu and the reference density rho0. However, to avoid confusion with the magnetic permeability µm
we will make the solver directly read the kinematic viscosity:
This way, the user only needs to input the kinematic viscosity in the transportProperties file,
similarly to the mhdFoam solver. In these conditions, it must be taken into consideration that the
kinematic viscosity input here should be calculated with the reference density ρo at the reference
temperature To .
We will then complete the file by adding the following new properties to read: the fluid specific
heat, cp , the channel lengths, a and b, the Hartmann brake time, τHa (tauHa in the code), the base
volumetric heat deposition, qo , the exponential shape parameter, m, and the direction of the heat
deposition expressed in the coord parameter.
dimensionedScalar a
(
transportProperties.lookup("a")
);
dimensionedScalar b
(
transportProperties.lookup("b")
);
dimensionedScalar sigma
(
transportProperties.lookup("sigma")
);
dimensionedScalar tauHa
(
b*sqrt(rho0/(sigma*nu))
);
dimensionedScalar q0
(
transportProperties.lookup("q0")
);
dimensionedScalar m
(
transportProperties.lookup("m")
);
scalar coord
(
readScalar(transportProperties.lookup("coord"))
);
Note that tauHa is calculated similarly to Eq. (2.22) but without the magnetic field since this is
provided later as a field. Therefore, tauHa won’t match the time dimensions in our code. coord will
take the values of 1, 2 or 3 if the heat deposition is given in the X, Y , or Z-axis, respectively, as it
will be shown in the createFields.H file.
27
4.1. Implementation of the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
Modifying createFields.H
The magnetic field must be initialized and the heat deposition source field must be calculated in
the createFields.H file. We will add the next code block to that file.
The piece of code corresponding to the construction of the magnetic field B is the same used by the
mhdFoam solver, differing in that here we use a volScalarField object instead of a volVectorField
object. With this configuration, the solver is always considering the 2D problem in the plane formed
by the direction of the flow and the direction of the heat deposition—both perpendicular to the
actual magnetic field—, forcing the user to fit the conditions of the quasi-2D formulation. Also, the
magnetic field must be provided in the 0 time directory and will be written similarly to the other
fields. We will not use non-constant magnetic fields in the examples of this report, but the code
allows it as long as this field is perpendicular to the aforementioned plane.
After the construction of the magnetic field, the heat deposition field, called sourceT is built
following Eq. (2.15) with dimensions of W/m3 . The boundary conditions of the sourceT field are
28
4.1. Implementation of the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
configured in the object sourceTBCTypes in lines 17–21 of the code above. The name of each bound-
ary is copied from the pressure field (but it could be done from any other existing field). We don’t
want the field to be affected by the boundaries, therefore, all of them are set to the zeroGradient
boundary condition type. The coord parameter is then used to determine the direction in which
the heat deposition is distributed and, finally, in line 46, the sourceTBCTypes object is used when
creating the sourceT field.
Next, we will modify the momentum equation to add the magnetic body field term as defined
in Section 2.7 and the energy equation with the new heat deposition term. The new term in the
conservation of momentum depends, besides the magnetic field, on the Hartmann brake time defined
in the previous steps and in the velocity field, which will be explicitly defined in order to be included
in the solution matrix. This term will cause the flattened velocity profile characteristic of MHD
flow. The momentum equation is located in the Q2DmhdFoam.C file and we will add the next term
after the equal sign of the UEqn.
solve(UEqn == -fvc::grad(p));
Sp is the operator defined to add an implicit source term. The heat deposition term is added
to the energy equation. Note the physical parameters rho0 and Cp (density and specific heat) that
need to be added to fit the dimensions of the energy equation.
We also want to include some extra lines to make the code automatically adjust the time step so
that the maximum Courant number does not overcome a specific threshold for the stability of the sim-
ulations. The code able to perform this task is widespread in other FOAM solvers and there are some
include files in the installed library that can do this. The files createTimeControls.H, CourantNo.H,
setInitialDeltaT.H, readTimeControls.H and setDeltaT.H allow reading the configuration pa-
rameters in the controlDict file and, if user wants to run an adjustable runtime simulation, they
are used to recalculate the time step each iteration to fit a maximum Courant number.
29
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
Included code at the beginning of the Q2DmhdFoam.C file. New lines in red.
...
#include "fvCFD.H"
#include "pisoControl.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
# include "setRootCase.H"
# include "createTime.H"
# include "createMesh.H"
pisoControl piso(mesh);
# include "readTransportProperties.H"
# include "readGravitationalAcceleration.H"
# include "createFields.H"
# include "initContinuityErrs.H"
# include "createTimeControls.H"
# include "CourantNo.H"
# include "setInitialDeltaT.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
while (runTime.loop())
{
Info<< "Time = " << runTime.timeName() << nl << endl;
# include "readTimeControls.H"
# include "CourantNo.H"
# include "setDeltaT.H"
...
At this point, one should compile the code with the wmake command and verify everything is
correct.
30
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
The generated mesh must be like the one previously seen in Figure 3.1 for the hartmann tutorial.
Then we will configure the fields of the 0 time folder. This will consist in firstly copying the
magnetic and velocity fields from the Hartman tutorial:
cp $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann/0/B 0/B
cp $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann/0/U 0/U
and adapting the boundaries of the rest of fields, pressure and temperature, to fit those of the original
hartmann tutorial:
sed -i s/top/inlet/g 0/*
sed -i s/bottom/outlet/g 0/*
sed -i s/left/upperWall/g 0/*
sed -i s/right/lowerWall/g 0/*
The pressure file, 0/p needs further modifications. Since the original case was a closed cavity, all
boundary conditions were zeroGradient. But now we have a channel with an inlet and an outlet
and we need to specify a pressure value at some point since the solver calculates pressure gradients
and a reference point is needed. The change is shown below:
Initial conditions in the pressure file.
| ========= | |
| \\ / F ield | foam-extend: Open Source CFD |
| \\ / O peration | Version: 4.1 |
| \\ / A nd | Web: http://www.foam-extend.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0;
boundaryField
{
inlet
{
type zeroGradient;
}
outlet
{
type fixedValue;
value uniform 0;
}
upperWall
{
type zeroGradient;
}
lowerWall
{
type zeroGradient;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //
Finally, we will also modify the temperature values to 0, since we do not want to take into
account any buoyancy effect in this first case. The T file looks like:
31
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
dimensions [0 0 0 1 0 0 0];
internalField uniform 0;
boundaryField
{
inlet
{
type zeroGradient;
}
outlet
{
type zeroGradient;
}
upperWall
{
type fixedValue;
value uniform 0;
}
lowerWall
{
type fixedValue;
value uniform 0;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //
If, at this point, we try to run the case with Q2DmhdFoam, the solver would complain that
some properties are missing in the transportProperties file. These are the properties defined in
the solver’s file readTransportProperties: a, b, sigma, q0, m and coord. After modifying the
transportProperties file, its aspect is as follows.
32
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
// ************************************************************************* //
The file is configured to repeat similar conditions to the hartmann tutorial. The buoyancy-related
properties are set so that no temperature effect takes place at this stage. For the same purpose we
will also change the gravity to 0 in the constant/g file.
g file.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | foam-extend: Open Source CFD |
| \\ / O peration | Version: 4.1 |
| \\ / A nd | Web: http://www.foam-extend.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class uniformDimensionedVectorField;
location "constant";
object g;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -2 0 0 0 0];
value ( 0 0 0 );
// ************************************************************************* //
Regarding the controlDict file, we will copy that of the hartmann tutorial and change its default
solver to Q2DmhdFoam.
cp $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann/system/controlDict \
system/controlDict
sed -i s/mhdFoam/Q2DmhdFoam/g system/controlDict
and change the laplacian scheme in system/fvSchemes, since our changes in the solver yield some
problems with this.
33
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
Finally, there is a sampleDict file that was included in the heatedCavity tutorial. We will
change its content to fit the following code
sampleDict file.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | foam-extend: Open Source CFD |
| \\ / O peration | Version: 4.1 |
| \\ / A nd | Web: http://www.foam-extend.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object sampleDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
interpolationScheme cellPoint;
setFormat raw;
sets
(
line_centreProfile
{
type uniform;
axis distance;
start (10.001 -1 0.01);
end (10.001 1 0.01);
nPoints 100;
}
);
surfaceFormat null;
surfaces
();
fields
(
U
);
// ************************************************************************* //
This file will help to obtain velocity profile data for visualization.
With the case set up, the Q2DmhdFoam solver can be run. Figure 4.1 shows a comparison between
the velocity profile with the configuration so far (purple) and the same case with no magnetic field
(green). It can be seen how the typical parabolic laminar profile is flattened in the presence of a
magnetic field.
cd $FOAM_RUN
cp -r liquidMetalChannel liquidMetalChannelHeated
cd liquidMetalChannelHeated
We will then modify the fields to fit the new case. We change the temperature boundary condi-
tions, in this case, to avoid heat transfer through the walls, and set the internal field to 500 °C:
34
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
The rest of the fields do not need further modifications and the sourceT field will be generated
automatically.
Next, the physical properties in the transportProperties file need to be modified:
35
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
// ************************************************************************* //
Here, a base heat deposition q0 of 50 W/m3 is enough to show buoyancy effects in the velocity
profile.
The acceleration of gravity also needs to be added since we set it to zero before. Since our fluid
flows in the X direction, we set the gravity to the negative X direction to simulate a vertical channel:
dimensions [0 1 -2 0 0 0 0];
value ( -9.81 0 0 );
// ************************************************************************* //
Finally, we will modify the end time in the controlDict file. Because the temperature field will
evolve from the initial conditions—initially set to a uniform internal value—the case needs more time
than the liquidMetalChannel case to reach steady-state conditions. An endTime of 60 seconds is
enough to this aim.
36
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
...
endTime 60;
...
// ************************************************************************* //
The case can now be run with the Q2DmhdFoam solver. Using a visualization tool such as paraview
the deposition term exponential shape can be verified as it can be seen in Figure 4.2.
37
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver
38
Chapter 5
In this chapter, we will perform a validation of the Q2DmhdFoam code. For this, the analytical solution
shown by Tagawa, Authié and Moreau [7] will be used. Also, the capabilities of Python code to
perform pre-processing and post-processing tasks will be used. The Python executable present in
the accompanying files performs the following tasks:
Calculates the proper mesh configuration based on the parameters (mainly the magnetic field).
Post-processes the output data to show the results of the validation concerning the analytical
solution.
39
5.2. Validation procedure Chapter 5. Validation and postprocessing
The analytical solution for the bulk flow provided by Tagawa et al. is
Gr
Wbulk = θ (5.3)
2Ha
which is a simple linear solution that only depends on dimensionless parameters. We will use this
formula and the maximum velocities to validate the solver.
cd $FOAM_RUN
cp -r liquidMetalChannelHeated baseCaseTagawa
cd baseCaseTagawa
The initial field files shall contain the following. Note that the geometry will consist of a long
enclosure (emulating the infinite enclosure of Tagawa et al.), therefore all 2D boundaries should look
the same except for the temperature boundaries, which are the base for the heat flux in the channel.
40
5.2. Validation procedure Chapter 5. Validation and postprocessing
41
5.2. Validation procedure Chapter 5. Validation and postprocessing
boundaryField
{
inlet
{
type zeroGradient;
}
outlet
{
type zeroGradient;
}
lowerWall
{
type zeroGradient;
}
upperWall
{
type zeroGradient;
}
frontAndBack
{
type empty;
}
}
Here, we have introduced the /Ux/, /T0/, /Th/, /Tc/ and /B/ tags that will be replaced by the
initial velocity, bulk temperature, hot wall temperature, cold wall temperature, and magnetic field.
Next, we insert the tags for the physical properties for liquid metal and gravity acceleration in
transportProperties and g files.
nu nu [0 2 -1 0 0 0 0] /nu/;
T0 T0 [0 0 0 1 0 0 0] /T0/;
Cp Cp [0 2 -2 -1 0 0 0] /Cp/;
k k [1 1 -3 -1 0 0 0] /k/;
a a [0 1 0 0 0 0 0] /a/;
b b [0 1 0 0 0 0 0] /b/;
q0 q0 [1 -1 -3 0 0 0 0] /q0/;
m m [0 0 0 0 0 0 0 ] /m/;
42
5.2. Validation procedure Chapter 5. Validation and postprocessing
Nx /Nx/;
Ny /NyBulk/;
NyBL /NyBL/;
Gy /GyBulk/;
GyInv /GyBulkInv/;
GyBL /GyBL/;
GyBLinv /GyBLinv/;
vertices
(
(0 $yNeg 0)
($x $yNeg 0)
($x $yNegBL 0)
(0 $yNegBL 0)
(0 $yNeg 0.1)
($x $yNeg 0.1)
($x $yNegBL 0.1)
(0 $yNegBL 0.1)
(0 0 0)
($x 0 0)
($x $yBL 0)
(0 $yBL 0)
(0 0 0.1)
($x 0 0.1)
($x $yBL 0.1)
(0 $yBL 0.1)
(0 $y 0)
($x $y 0)
(0 $y 0.1)
($x $y 0.1)
);
blocks
(
hex (0 1 2 3 4 5 6 7) ($Nx $NyBL 1) simpleGrading (1 $GyBL 1)
hex (3 2 9 8 7 6 13 12) ($Nx $Ny 1) simpleGrading (1 $Gy 1)
hex (8 9 10 11 12 13 14 15) ($Nx $Ny 1) simpleGrading (1 $GyInv 1)
hex (11 10 17 16 15 14 19 18) ($Nx $NyBL 1) simpleGrading (1 $GyBLinv 1)
);
...
Here, it can be seen that many tags are defined to configure the 2D mesh in terms of number of
cells, lengths and gradings. Four blocks are set for the two boundary layers and two bulk zones, and
their grading will be calculated in the next section to reduce the number of cells and computational
time. The relation of tags regarding meshing can be found in Table 5.2.
A mesh using this configuration can be seen in Figure 5.1. This example was calculated with
a very small Hartmann number (Ha=1) for the boundary layer to be wider and therefore better
visualization. This image shows how the boundary layers have higher cell grading due to the steepest
gradients that may take place at high Hartmann numbers. The bulk has a smoother grading and it
is split into two zones for symmetry reasons.
43
5.2. Validation procedure Chapter 5. Validation and postprocessing
Tag Explanation
Position tags
Lx x-axis length
LyBulk Higher y positive location
LyNegBulk Higher y negative location
LyBL Start of positive side boundary layer
LyNegBL Start of negative side boundary layer
Number of cells tags
Nx Cells in the x-axis
NyBulk Cells in the half-bulk region
NyBL Cells in the boundary layer region
Grading tags
GyBulk Grading for the bulk
GyBulkInv Inverse of GyBulk
GyBL Grading for the boundary layer
GyBLInv Inverse of GyBL
44
5.2. Validation procedure Chapter 5. Validation and postprocessing
The last tagged file is the sampleDict file, which will be used to produce raw data for plotting
velocity profiles:
Contents of the system/sampleDict file for the tagawa validation.
interpolationScheme cellPoint;
setFormat raw;
sets
(
line_centreProfile
{
type uniform;
axis distance;
start (/LxHalf/ -/a/ 0.01);
end (/LxHalf/ /a/ 0.01);
nPoints 1000;
}
);
surfaceFormat null;
surfaces
();
fields
(
U
);
This file has been modified to measure the velocity profile in the center of the domain (LxHalf tag).
We also include in this section the main contents of the controlDict file, which is set up with
a sufficiently large end time to reach steady state, with the adjustable time step feature (see the
solver implementation in Chapter 4), and a safe maximum Courant number.
Contents of the system/controlDict file for the tagawa validation.
application Q2DmhdFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 5000;
deltaT 0.005;
writeControl adjustableRunTime;
writeInterval 5000;
...
adjustTimeStep yes;
maxCo 0.5;
Prior to going any further, one must make sure that the baseCaseTagawa directory doesn’t
contain any temporal file that might interfere with the later script process.
5.2.2 Scripting
In this section we will check the contents of the script that will automate the validation procedure.
45
5.2. Validation procedure Chapter 5. Validation and postprocessing
The first part of the main file, meshAndGo.py imports the necessary packages and procedures
and it reads the MHDinput external text file in which we have input the Hartmann, Reynolds and
Grashof numbers.
meshAndGo.py file. Part I.
#!/usr/bin/env python3
import MHDutils as utils
import numpy as np
import matplotlib.pyplot as plt
import subprocess as sp
import os
######################
### INITIALIZATIONS
######################
# Get main parameters from input file
param = np.loadtxt('MHDinput', unpack=True, skiprows=2)
Ha = param[0]
Re = param[1]
Gr = param[2]
MHDinput file.
# Input here the three parameters that define the case
# 1. Hartmann; 2. Reynolds; 3. Grashof
100
0
1e4
The MHDutils module exists in an external file, MHDutils.pyc, included in the accompanying
files with auxiliary Python functions to deal with repetitive tasks such as substituting tags in files
by their desired value. MHDutils.pyc is a Python compilated file and, therefore, its contents are not
visible to the user.
Next, the script defines the dictionaries that will be used:
meshAndGo.py file. Part II.
# Define main tag dictionary
tag_dict = {
'B' : '?',
'Ux' : '?',
'T0' : 0.0,
'a' : 0.15/2,
'b' : 0.15/2,
'q0' : 0,
'qWall' : 0,
'm' : 1,
'Th' : '?',
'Tc' : '?',
'g' : -9.81,
'rho0' : 9720,
'nu' : 1.54e-7,
'Cp' : 189,
'k' : 22.36,
'beta' : 1.2e-4,
'sigma' : 763000
}
tag_dict.update(phys_dict)
At this point, the physical parameters mentioned in Section 5.1 are saved into a Python dictionary
that will be handled by the tagging functions. Some values still unknown are stored temporarily as
‘?’.
Now, a new directory called tagawa is created from the baseCaseTagawa modified in Section 5.2.1.
We thus always keep a clean copy of the baseCaseTagawa so we only modify the new directory. The
subprocess module imported at the beginning of the script helps us handling terminal commands:
46
5.2. Validation procedure Chapter 5. Validation and postprocessing
The parameters read from MHDinput are then used to calculate the velocity (in this case v =
0), the magnetic field and the temperature boundaries. These values are stored in the tag_dict
dictionary, where they were unknown before. The formulas from Section 2.5 are used:
Now we calculate the main parameters that will determine the√mesh. This is based on considering
the proportionality of the side boundary
√ layer to the inverse of Ha. For our case, considering the
width of the side boundary layer as a/ Ha works fine.
print('Ha = {}'.format(Ha))
print('SIDE BOUNDARY LAYER')
print('side boundary length = {}'.format(l_side))
print('G = {}'.format(G_bl))
print('cmax = {}'.format(cmax))
The lenC2CN function from the MHDutils module calculates the grading for a certain length
and number of cells, and lenCminC2C uses a Python optimization library to get the grading and
number of cells from a certain length and minimum cell size. Both are used to get a suitable grading
47
5.2. Validation procedure Chapter 5. Validation and postprocessing
following geometric progressions, and so that the change between the boundary layer blocks and the
bulk blocks is smooth.
After this step, all mesh-related tags appearing in table 5.2 are stored, calculated and added to
the tag_dict dictionary. The latter is finally used by the replaceTags function, which searches
the whole case directory for every file with tags (following the format given in section 5.2.1) that
matches those stored in the tag_dict dictionary, and replaces their value.
Now that the case directory is ready, the next piece code of our Python script calls the FOAM
commands blockMesh, Q2DmhdFoam and sample to run the case.
With the Q2DmhdFoam solver, running this kind of case is extremely fast and takes a few seconds.
The remaining task is the post-processing, which is performed by the next piece of code.
# Q2DmhdFoam solution
postProcess_dir = 'postProcessing/sets/'
latestTime = utils.getLatestTime(postProcess_dir)
raw_data_file = postProcess_dir + latestTime + '/line_centreProfile_U.xy'
y, Ux, Uy, Uz = np.loadtxt(raw_data_file, unpack=True)
y = y - tag_dict['a']
W = Ux / (tag_dict['nu'] / (2*tag_dict['a']))
ax.plot(y/(2*tag_dict['a']), W, label='Q2DmhdFoam')
48
5.3. Results Chapter 5. Validation and postprocessing
These last parts consists of calculating the analytical solution of the bulk velocity as shown by
Tagawa et al. and reading the output velocity data produced before by the sample command. In
the end, a plot overlaps the analytical and numeric results and this is saved as an image in eps
format as tagawaVal.eps saved inside the new tagawa directory.
5.3 Results
In a FOAM-sourced terminal window at the same directory level as the baseCaseTagawa directory
and the files meshAndGo.py, MHDutils.pyc and MHDinput as follows:
run
...
baseCaseTagawa
meshAndGo.py
MHDutils.pyc
MHDinput
...
we can run the main Python script. It is configured as an executable, so the user only needs to
run the following:
./meshAndGo.py
with the only constrain of having installed Python 3.8. Some terminal prompt pointing out the
substituted tags shall look like the following text:
49
5.3. Results Chapter 5. Validation and postprocessing
and, in a few seconds, a plot with the resulting velocity results should pop up and show something
similar to Figure 5.2.
10
5
Dimensionless velocity, W
−5
−10
−15
These results correspond to a dimensionless velocity calculated as shown in Section 5.1 plotted
versus the dimensionless distance. The velocity gradient in the center of the channel fairly agrees
with the desired results.
50
Bibliography
[1] J. Sommeria and R. Moreau, “Why, how, and when, MHD turbulence becomes two-dimensional,”
Journal of Fluid Mechanics, vol. 118, no. May, pp. 507–518, 1982.
[2] F. Urgorri, S. Smolentsev, I. Fernández-Berceruelo, D. Rapisarda, I. Palermo, and A. Ibarra,
“Magnetohydrodynamic and thermal analysis of PbLi flows in poloidal channels with flow channel
insert for the EU-DCLL blanket,” Nuclear Fusion, vol. 58, p. 106001, oct 2018.
[3] P. A. Davidson, An Introduction to Magnetohydrodynamics. Cambridge University Press, mar
2001.
[4] I. E. Sarris, G. K. Zikos, A. P. Grecos, and N. S. Vlachos, “On the Limits of Validity of the
Low Magnetic Reynolds Number Approximation in MHD Natural-Convection Heat Transfer,”
Numerical Heat Transfer, Part B: Fundamentals, vol. 50, pp. 157–180, may 2006.
[5] E. Mas de les Valls, Development of a simulation tool for MHD flows under nuclear fusion
conditions. PhD thesis, 2011.
[6] N. Vetcha, S. Smolentsev, and M. Abdou, “Theoretical study of mixed convection in poloidal
flows of dcll blanket,” Fusion Science and Technology, vol. 56, no. 2, pp. 851–855, 2009.
[7] T. Tagawa, G. Authié, and R. Moreau, “Buoyant flow in long vertical enclosures in the pres-
ence of a strong horizontal magnetic field. Part 1. Fully-established flow,” European Journal of
Mechanics, B/Fluids, vol. 21, no. 4, pp. 383–398, 2002.
[8] E. Mas De les Valls, L. A. Sedano, L. Batet, I. Ricapito, A. Aiello, O. Gastaldi, and F. Gabriel,
“Lead-lithium eutectic material database for nuclear fusion technology,” Journal of Nuclear
Materials, vol. 376, no. 3, pp. 353–357, 2008.
[9] D. Martelli, A. Venturini, and M. Utili, “Literature review of lead-lithium thermophysical prop-
erties,” Fusion Engineering and Design, vol. 138, pp. 183–195, jan 2019.
51
Study questions
1. What are the main disadvantages when simulating magnetohydrodynamic flow, even at low
magnetic Reynolds conditions?
2. What are the advantages of the Q2DmhdFoam solver versus other magnetohydrodynamic simu-
lation tools?
52
Appendix A
Developed codes
A.1 Q2DmhdFoam
Here, we include the most important files of the Q2DmhdFoam solver.
Q2DmhdFoam.C
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.1
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Application
Q2DmhdFoam
Description
Transient solver for 2D buoyancy-driven laminar magnetohydrodynamic
flow of incompressible conducting fluids using the Boussinesq Model and
the Sommeria and Moreau (1983) approximation
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "pisoControl.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
# include "setRootCase.H"
53
A.1. Q2DmhdFoam Appendix A. Developed codes
# include "createTime.H"
# include "createMesh.H"
pisoControl piso(mesh);
# include "readTransportProperties.H"
# include "readGravitationalAcceleration.H"
# include "createFields.H"
# include "initContinuityErrs.H"
# include "createTimeControls.H"
# include "CourantNo.H"
# include "setInitialDeltaT.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
while (runTime.loop())
{
Info<< "Time = " << runTime.timeName() << nl << endl;
# include "readTimeControls.H"
# include "CourantNo.H"
# include "setDeltaT.H"
fvVectorMatrix UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
- fvm::laplacian(nu, U)
==
-beta*(T - T0)*g
-fvm::Sp(mag(B)/tauHa, U)
);
solve(UEqn == -fvc::grad(p));
while (piso.correct())
{
volScalarField rUA = 1.0/UEqn.A();
U = rUA*UEqn.H();
phi = (fvc::interpolate(U) & mesh.Sf())
+ fvc::ddtPhiCorr(rUA, U, phi);
adjustPhi(phi, U, p);
while (piso.correctNonOrthogonal())
{
fvScalarMatrix pEqn
(
fvm::laplacian(rUA, p) == fvc::div(phi)
);
pEqn.setReference(pRefCell, pRefValue);
pEqn.solve();
if (piso.finalNonOrthogonalIter())
{
phi -= pEqn.flux();
}
}
# include "continuityErrs.H"
U -= rUA*fvc::grad(p);
54
A.1. Q2DmhdFoam Appendix A. Developed codes
U.correctBoundaryConditions();
}
runTime.write();
return(0);
}
// ************************************************************************* //
createFields.H
Info<< "Reading field p\n" << endl;
volScalarField p
(
IOobject
(
"p",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
55
A.1. Q2DmhdFoam Appendix A. Developed codes
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
# include "createPhi.H"
label pRefCell = 0;
scalar pRefValue = 0.0;
setRefCell(p, piso.dict(), pRefCell, pRefValue);
mesh.schemesDict().setFluxRequired(p.name());
56
A.1. Q2DmhdFoam Appendix A. Developed codes
"sourceT",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
q0*exp(- (y/a + 1) * m),
sourceTBCTypes
);
readTransportProperties.H
Info<< "Reading transportProperties\n" << endl;
IOdictionary transportProperties
(
IOobject
(
"transportProperties",
runTime.constant(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
dimensionedScalar rho0
(
transportProperties.lookup("rho0")
);
dimensionedScalar T0
(
transportProperties.lookup("T0")
);
dimensionedScalar nu
(
transportProperties.lookup("nu")
);
dimensionedScalar Cp
(
transportProperties.lookup("Cp")
);
dimensionedScalar DT
(
dimensionedScalar(transportProperties.lookup("k"))/
(rho0*Cp)
);
dimensionedScalar beta
(
transportProperties.lookup("beta")
);
dimensionedScalar a
(
transportProperties.lookup("a")
);
dimensionedScalar b
(
transportProperties.lookup("b")
);
dimensionedScalar tauHa
57
A.2. Python script Appendix A. Developed codes
(
b*sqrt(rho0/(dimensionedScalar(transportProperties.lookup("sigma"))*nu))
);
dimensionedScalar q0
(
transportProperties.lookup("q0")
);
dimensionedScalar m
(
transportProperties.lookup("m")
);
scalar coord
(
readScalar(transportProperties.lookup("coord"))
);
meshAndGo.py
#!/usr/bin/env python3
import MHDutils as utils
import numpy as np
import matplotlib.pyplot as plt
import subprocess as sp
import os
######################
### INITIALIZATIONS
######################
# Get main parameters from input file
param = np.loadtxt('MHDinput', unpack=True, skiprows=2)
Ha = param[0]
Re = param[1]
Gr = param[2]
58
A.2. Python script Appendix A. Developed codes
######################
### CASE CONDITIONS
######################
# Calculations from the parametrization of the problem and assign
# them to the dictionaries
B = Ha / (2*tag_dict['b']) * np.sqrt(tag_dict['nu'] * tag_dict['rho0'] /
tag_dict['sigma'])
Ux = Re * tag_dict['nu'] / tag_dict['a']
# Calculate delta_T from the input Grashof number
delta_T = Gr * tag_dict['nu']**2 / (abs(tag_dict['g']) * tag_dict['beta']
* (2*tag_dict['a'])**3 )
# Get hot and cold temperature for walls
Th = delta_T/2
Tc = -delta_T/2
# Tag and print values
tag_dict['B'] = B
tag_dict['Ux'] = Ux
tag_dict['Th'] = Th
tag_dict['Tc'] = Tc
print('Magnetic field B = {} for Ha = {}'.format(tag_dict['B'],Ha))
print('Mean velocity U = {} for Re = {}'.format(tag_dict['Ux'],Re))
print('Temperature difference is {} for Grashof = {}'.format(delta_T,Gr))
######################
### MESH
######################
l_side = tag_dict['a']/np.sqrt(Ha)
N_bl = 25
G_bl, _, cmax = utils.lenC2CN(l_side, N_bl)
print('Ha = {}'.format(Ha))
print('SIDE BOUNDARY LAYER')
print('side boundary length = {}'.format(l_side))
print('G = {}'.format(G_bl))
print('cmax = {}'.format(cmax))
mesh_dict = {
'Lx' : 200*tag_dict['a'],
'LxHalf' : 200*tag_dict['a'] / 2,
'LyBulk' : tag_dict['a'],
'LyBL' : tag_dict['a']-l_side,
'LyNegBulk' : -tag_dict['a'],
'LyNegBL' : -(tag_dict['a']-l_side),
'Nx' : 100,
'NyBulk' : N_bulk,
'NyBL' : N_bl,
'GyBulk' : G_bulk,
'GyBulkInv' : 1/G_bulk,
'GyBL' : G_bl,
'GyBLinv' : 1/G_bl
}
# Combine the mesh dictionary with the previous dictionary
tag_dict.update(mesh_dict)
59
A.2. Python script Appendix A. Developed codes
######################
### RUN CASE
######################
os.chdir(curr_dir)
sp.call("blockMesh > log.blockMesh", shell=True)
sp.call("Q2DmhdFoam > log.Q2DmhdFoam", shell=True)
sp.call("sample > log.sample", shell=True)
######################
### PLOT & VALIDATION
######################
# Analytical solution
T = np.linspace(Th,Tc)
theta = (T - 1/2*(Th + Tc))/(Th-Tc)
y_analytic = np.linspace(-tag_dict['a'],tag_dict['a'])
W_analytic = Gr/(2*Ha) * theta
fig, ax = plt.subplots(figsize=(12,12))
ax.plot(y_analytic[10:-10]/(2*tag_dict['a']), W_analytic[10:-10], label='Bulk analytical solution')
# Q2DmhdFoam solution
postProcess_dir = 'postProcessing/sets/'
latestTime = utils.getLatestTime(postProcess_dir)
raw_data_file = postProcess_dir + latestTime + '/line_centreProfile_U.xy'
y, Ux, Uy, Uz = np.loadtxt(raw_data_file, unpack=True)
y = y - tag_dict['a']
W = Ux / (tag_dict['nu'] / (2*tag_dict['a']))
ax.plot(y/(2*tag_dict['a']), W, label='Q2DmhdFoam')
# Plot config
ax.set_xlabel('Dimensionless length, $X=x/l$')
ax.set_ylabel('Dimensionless velocity, $W$')
ax.legend(loc='upper right')
plt.show()
fig.savefig('tagawaVal.eps',format='eps',dpi=1000)
60
Index
61