You are on page 1of 62

Cite as: Iraola, E.

: Implementation of quasi-2D magnetohydrodynamic mixed convection solver for


incompressible flows in liquid metal channels. In Proceedings of CFD with OpenSource Software, 2020,
Edited by Nilsson. H., http://dx.doi.org/10.17196/OS CFD#YEAR 2020

CFD with OpenSource software


A course at Chalmers University of Technology
Taught by Håkan Nilsson

Implementation of quasi-2D
magnetohydrodynamic mixed convection
solver for incompressible flows in liquid
metal channels

Developed for foam-extend-4.1,


nextRelease
Requires: Python 3.8

Author: Peer reviewed by:


Eduardo Iraola de Acevedo Saeed Salehi
Technical University of Catalonia Chirayu Batra
eduardo.iraola@upc.edu Daniel Suárez Cambra
Lluı́s Batet Miracle

Licensed under CC-BY-NC-SA, https://creativecommons.org/licenses/

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.

January 31, 2021


Learning outcomes

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.

The reader will learn:

How to use it:

ˆ How the boussinesqBuoyantFoam solver is used.

ˆ How the mhdFoam solver is used.

The theory of it:

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

ˆ Fundamentals of Computational Methods for Fluid Dynamics, Book by J. H. Ferziger and M.


Peric, specifically regarding conservation of momentum and energy equation.

ˆ How to run OpenFOAM tutorials such as cavity or damBreak.

ˆ How to customize a OpenFOAM solver and do top-level application programming.

ˆ Fundamental usage of visualization tools such as paraview and gnuplot.

ˆ Python programming skills.

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

4 The Q2DmhdFoam solver 24


4.1 Implementation of the Q2DmhdFoam solver . . . . . . . . . . . . . . . . . . . . . . . . 24
4.2 Using the Q2DmhdFoam solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2.1 Configuring the first case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2.2 Observing buoyancy effects with Q2DmhdFoam . . . . . . . . . . . . . . . . . . 34

5 Validation and postprocessing 39


5.1 Validation case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.2 Validation procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.2.1 Case configuring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.2.2 Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.3 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

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.

2.1.1 The coupling of momentum and electromagnetic equations


Maxwell’s equations are a set of equations that, along with the Lorentz force law, lie in the field of
classical electromagnetism. Maxwell’s equations are formed by four equations that are summarized
in the following paragraphs.
The first of them is the differential form of Gauss’s law and it is related to the idea that any
surface that confines the same amount of charge is crossed by the same flux of electrical field, E.
Gauss’s law can be expressed as
ρc
∇·E = (2.1)
εm
where ρc is the charge density and εm is called the permittivity of the material.
The equation
∂B
∇×E =− (2.2)
∂t
is Faradays’s law of induction, which reflects the irrotational nature of electric field when it is
generated by static charge, and that electrical fields can also be generated by a changing magnetic
field, B.
The third of Maxwell’s equations states the solenoidal nature of a magnetic field. This means
that the magnetic field lines, unlike electric field’s, are closed and monopoles cannot be conceived in
classical electromagnetism. The third of Maxwell’s equations or Gauss’s law for magnetism is given
by
∇·B =0 (2.3)
The last of this set of equations is Ampère’s law,
∂E
∇ × B = µm j + µm εm (2.4)
∂t
and states the non-zero curl nature of magnetic fields, differently than electric fields in electrostatics.
µm stands for the magnetic permeability of the material. The first right-hand term in Eq. (2.4)
refers to the generation of a magnetic field by any current density j. The second term is the
displacement current and describes the fundamental physics concept of reciprocal magnetic-electric
field generation: not only changing magnetic fields create electric fields, but changing electric fields
also breed magnetic fields.

6
2.1. Magnetohydrodynamics Chapter 2. Background

Maxwell’s equations can be simplified for what is of interest in a magnetohydrodynamic liquid


metal flow as
∂B
∇×E =− (2.5a)
∂t
∇·B =0 (2.5b)
∇ × B = µm j (2.5c)
considering a grossly neutral fluid. Gauss’s law is omitted since it is assumed there is no charge
distribution in the system.
Furthermore, charge conservation equation,

∇·j =0 (2.6)

Ohm’s law for electric current density,

j = σ(E + v × B) (2.7)

and Lorentz force’s law,


fm = j × B (2.8)
need to be used in an MHD solver. fm and σm stand for the magnetic force per unit volume and
the electrical conductivity of the material, respectively.
Since the magnetic force can significantly influence the flow regime when considering an elec-
trically conducting fluid, it should be taken into account when solving the momentum equation in
hydrodynamic problems influenced by electromagnetism. The body force term can be included as
B2
 
∂v ∇p 1
+ (v · ∇)v = − + ν∇2 v + −∇ + (B · ∇)B (2.9)
∂t ρ µm ρ 2
Its derivation is explained by Davidson [3].
On the other hand, a magnetic field equation,
∂B 1
= ∇ × (v × B) + ∇2 B (2.10)
∂t σµm
is obtained from Eqs. (2.5a), (2.5c), (2.6), (2.7) and (2.8).
The magnetic equation in Eq. (2.10) is coupled with the velocity field and, together with Gauss’s
law for magnetism (Eq. (2.5b)), conservation of momentum (Eq. (2.9)) and conservation of mass,
constitutes the set of equations to be solved for pure magnetohydrodynamics.

2.1.2 Low magnetic Reynolds approximation


The electric current induced by a magnetic field in a conducting material tends to deform the
magnetic field lines by creating new magnetic field components that modify the original magnetic
field in the domain. If representative, the MHD codes must take this into account, making the
resolution more complex.
In some circumstances, this effect can be neglected and help to simplify the codes. To quantita-
tively evaluate the importance of self-induction, the magnetic Reynolds dimensionless number, Rm ,
defined as
vo L
Rm = (2.11)
η
where the parameter η = 1/(σm µm ), can be used. It is commonly accepted that, in conditions of
Rm  1, the low magnetic Reynolds approximation can be used [4], thus simplifying the set of
equations needed. In this situation, the magnetic field is practically homogeneous, the 3-component
Eq. (2.10) can be simplified and the current density can be explicitly evaluated by Eq. (2.7), which
makes algorithms simpler and allows to reduce computational effort. The low magnetic Reynolds
approximation can be assumed in the case of liquid metal under magnetic fields in fusion breeding
blankets [5], which is the sub-field of MHD this report focuses on.

7
2.2. The Boussinesq approximation Chapter 2. Background

2.2 The Boussinesq approximation


The density of a fluid depends on the temperature. Therefore, the energy and momentum equations
are generally coupled and temperature influence in the velocity profile is important in liquid metal
experiencing heavy temperature gradients. However, since the expansion coefficient, β, of liquid
PbLi is small (an order of magnitude lower than gases), the Boussinesq hypothesis can be used [5].
The Boussinesq hypothesis lets us use a constant density ρo in all the terms of the momentum
equation except in the buoyancy term, instead of using an equation of state. The momentum and
energy equations are coupled by the buoyancy term,

β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

2.3 The Energy equation and the source term


A simple expression of the energy equation in terms of the temperature can be set as
∂T k 2
+ (v · ∇)T = ∇ T (2.14)
∂t ρcp

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.

2.4 Complete MHD equations


This section provides the complete set of equations for magnetohydrodynamic incompressible flow
with temperature-velocity coupling, magnetic field-velocity coupling and exponential heat deposi-
tion.

∇·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

2.5 Dimensionless numbers


In this section, we show some important dimensionless quantities for the parameterization of liquid
metal MHD cases. In liquid metal flows, the main non-dimensional numbers that describe the regime
of the system are Reynolds, Hartmann and Grashof numbers [2].
The Reynolds number, Re, is a well-known number in hydrodynamic. It relates inertial forces
with viscous forces and, qualitatively, if viscous forces are considerably higher than inertial ones, the
Reynolds number is low and the flow tends to be laminar instead of turbulent, and vice versa. It is
calculated by the formula
ρvo L
Re = (2.17)
µ
where L is the characteristic length of the flow.
The Hartmann number, Ha, expresses the relationship between magnetic forces with viscous
forces. Specifically, the square of this number represents the relation of Lorentz forces with respect
to viscous forces, as it can be seen in r
σ
Ha = Bb (2.18)
µ
Here, b is the characteristic length in the direction of the magnetic field, corresponding to half the
distance between walls in square ducts.
In the lithium-lead (PbLi) breeding blanket concepts for nuclear fusion, the order of magnitude
of the Hartmann number varies from 103 to 104 . From these high values, it can be inferred the
dominant role of the MHD interactions over viscous effects in the PbLi dynamics [2].
The Grashof number, Gr, represents the ratio between the buoyancy forces and the viscous forces
in

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.

2.6 Characteristic MHD flow


Figure 2.1 shows the cross-section in the magnetohydrodynamic case of a square channel with the
main geometric parameters and direction of the involved fields. The flow goes along the x direction
(the ⊗ symbol indicates that the positive x direction goes into the plane, away from the reader)
and an external magnetic field is applied in z direction. The walls parallel to the magnetic field are
called side walls and the walls perpendicular to that field have the name of Hartmann walls.

9
2.6. Characteristic MHD flow Chapter 2. Background

Hartmann wall

Hartmann boundary layer

δHa

Side boundary layer

Side boundary layer


Side wall

Side wall
2b

δside

Hartmann boundary layer

δ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

2.7 Quasi-2D magnetohydrodynamic flow


Sommeria and Moreau [1], when trying to analyze turbulent MHD flow in electrically insulating
channels, discovered that, in conditions of low magnetic Reynolds, high Reynolds and high magnetic
fields, the MHD flow behave as a quasi-two-dimensional flow in the plane perpendicular to the
magnetic field.
In this approach, the authors were interested in the influence of the Hartmann layers (see Figure
2.1) in the bulk of the flow region. They concluded that the fluid in the different two-dimensional
planes—formed by the direction of the flow and the direction perpendicular to the magnetic field—
were influenced by each other by means of electromagnetic forces and viscous effects. Particularly,
the current density, as previously seen in Figure 2.2 (left), tends to accumulate in the Hartmann
layers and, because of charge conservation, the electric current must be closed along the bulk region,
generating a braking effect there. In a 2D approximation, they expressed this braking effect with a
simple extra term in the momentum equation
∂v 1 1
+ (v · ∇)v = − ∇p + ν∇2 v − v (2.21)
∂t ρ τHa
where τHa is called the Hartmann braking time and takes de form of
r
b ρ
τHa = (2.22)
B σν
Besides, as pointed out by Vetcha, Smolentsev and Abdou [6], the Boussinesq approach can be
added to the momentum equation to take into account buoyancy forces, which leaves us with
∂v 1 1
+ (v · ∇)v = − ∇p + ν∇2 v − v + βg(T − To ) (2.23)
∂t ρ τHa
Therefore, Eq. (2.23) applies to planes perpendicular to the magnetic field and provides a sim-
ple fast tool to analyze buoyant, magnetohydrodynamic flows, specially compared with the set of
equations (2.16).

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.

3.1 The mhdFoam solver


The mhdFoam solves magnetohydrodynamic, incompressible, laminar flow of a conducting fluid in
the presence of a magnetic field. It is available in the foam-extend 4.1 Next Release distribution
used in this tutorial and also in OpenFOAM v2006.
This section will briefly show how the mhdFoam solver is implemented using the fundamentals
shown in Chapter 2 and how to use the tutorial included in the aforementioned foam-extend dis-
tribution to further understand how the solver works.

3.1.1 Implementation of mhdFoam


mhdFoam uses the momentum equation coupled with the magnetic field as in Eq. (2.9) without the
low-Rm approximation.

Implementation of the momentum equation for mhdFoam in the mhdFoam.C file.


fvVectorMatrix UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
- fvc::div(phiB, 2.0*DBU*B)
- fvm::laplacian(nu, U)
+ fvc::grad(DBU*magSqr(B))
);

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

3.1.2 Using the hartmann tutorial


The hartmann tutorial included in the foam-extend 4.1 distribution shows a case of a 2D Hartmann
channel that represents an MHD flow between two infinite electrically insulating plates. The tutorial
includes the typical case directory organization:
hartmann
0
B
p
pB
U
constant
polymesh
blockMeshDict
transportProperties
system
controlDict
fvSchemes
fvSolution
sampleDict
Note that the main difference with respect to the tutorial in the OpenFOAM v2006 distribution
is the location of the blockMeshDict dictionary, which is placed inside the system directory in the
latter.
Before running the case, the user must configure the main properties in the transportProperties
file sets the value of the density of the fluid, rho, the kinematic viscosity, nu, the magnetic perme-
ability, mu, and the electric conductivity, sigma (by default, all of them are set to 1).
The fields in the zero-time directory must be initialized and the focus should be put on the velocity
and magnetic fields. The B internal field has a default uniform value of 20 T in the y direction, which
can vary along the simulation time due to the effects of autoinduction, and fixedValue boundary
conditions of also 20 T for the upper and lower wall. The rest of the 2D boundaries are of type
zeroGradient. For the velocity field, U, the inlet velocity is fixed to 1 m/s, and the internal field,

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 Magnetic Field

Hartmann wall
Velocity

Figure 3.1: Mesh generated from the hartmann tutorial.

When running the hartmann tutorial with the command:


mhdFoam
without any modifications, a square 2D velocity profile must be obtained (recall Figure 2.2) and the
thin Hartmann boundary layers shall be seen. This is shown in Figure 3.2.
However, if we are interested in the side boundary layers this configuration does not work. First
of all, following the field configuration of Figure 2.1, the magnetic field should be changed to be
perpendicular to the current geometry plane, since side layers are parallel to the magnetic field.
But, if we perform this change in the current configuration, the case will not work because the case
is configured to be two-dimensional and the induced currents in a particular section are forced to
go in only one direction, therefore unable to satisfy the conservation of charge. So to reproduce the
behavior of the side boundary layers, it is necessary to modify the case into a three-dimensional
channel. We will show how to do this in a few steps, starting by copying a fresh hartmann tutorial
into a new case that we will call hartmann3D:
cd $FOAM_RUN
cp -r $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann hartmann3D
cd hartmann3D
First, the blockMeshDict needs to be modified to allow the patches in the third dimension to
operate and adding a number of cells in that direction. As shown in the code below, we chose to
have a square duct from z = −1 to z = 1 with 40 cells in that direction.

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.

/*--------------------------------*- 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 blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

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
(
);
// ************************************************************************* //

The mesh generated with this configuration is shown in Figure 3.3.

wall
Side

ll
n wa
an
artm
H
Velocity

Magnetic Field

Figure 3.3: Mesh generated from the hartmann3D tutorial.

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.

internalField uniform (0 0 20);

boundaryField
{

...

frontAndBack
{
type fixedValue;
value uniform (0 0 20);
}
}

For the velocity field, a no-slip condition is imposed:

Modified frontAndBack velocity boundary condition (0/U) for the hartmann3D case.
boundaryField
{

...

frontAndBack
{
type fixedValue;
value uniform (0 0 0);
}
}

Finally, the pressures must have zero-gradient boundary conditions:

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

New system/sampleDict file for the hartmann3D case.


/*--------------------------------*- 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_side
{
type uniform;
axis distance;
start (10.001 -1 0);
end (10.001 1 0);
nPoints 100;
}
line_centreProfile_hartmann
{
type uniform;
axis distance;
start (10.001 0 -1);
end (10.001 0 1);
nPoints 100;
}

);
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.

3.2 The boussinesqBuoyantFoam solver


When the user wants to simulate a buoyant flow, he/she finds that foam-extend offers a variety of
solvers to this end. In the heatTransfer set of solvers it can be found the next list of items:
applications

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):

ˆ boussinesqBuoyantFoam. Transient solver for buoyant, laminar flow of incompressible Newto-


nian fluids using the Boussinesq hypothesis. It uses the PISO algorithm to obtain the transient
states.
ˆ buoyantBoussinesqPisoFoam. Transient solver for buoyant, turbulent flow of incompressible
fluids using the Boussinesq hypothesis. It uses the PISO algorithm to obtain the transient
states.
ˆ buoyantBoussinesqSimpleFoam. Steady-state solver for buoyant, turbulent flow of incom-
pressible fluids using the Boussinesq hypothesis. It uses the SIMPLE algorithm to obtain the
steady-state solution.

ˆ 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

ˆ buoyantSimpleRadiationFoam. Steady-state solver for buoyant, turbulent flow of compress-


ible fluids. It uses the SIMPLE algorithm and includes radiation modeling.

3.2.1 Implementation of boussinesqBuoyantFoam


Here, we focus on the first of them: the boussinesqBuoyantFoam solver. This solver adds the
buoyancy term to the momentum equation like Eq. (2.13) as it is shown in the next piece of code
extracted from the boussinesqBuoyantFoam.C file in the directory:
$FOAM_SOLVERS/heatTransfer/boussinesqBuoyantFoam

Implementation of the momentum equation for the boussinesqBuoyantFoam solver in the


boussinesqBuoyantFoam.C file.
fvVectorMatrix UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
- fvm::laplacian(nu, U)
==
-beta*(T - T0)*g
);

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.

Implementation of the energy equation for the boussinesqBuoyantFoam solver in the


boussinesqBuoyantFoam.C file.
// Solve energy equation
solve
(
fvm::ddt(T)
+ fvm::div(phi, T)
- fvm::laplacian(DT, T)
);

rho = rho0*(scalar(1) - beta*(T - T0));

3.2.2 Using the heatedCavity tutorial


There is a tutorial for buoyantBoussinesqFoam called heatedCavity that can be found under the
$FOAM_TUTORIALS/heatTransfer/boussinesqBuoyantFoam directory. By examining its directory
the next file structure can be found:
heatedCavity
0
p
T
U
constant
g
polymesh
blockMeshDict
transportProperties
system
controlDict

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.

Figure 3.5: Mesh used by the heatedCavity tutorial.

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

Definition of velocity boundary conditions (0/U) in the heatedCavity tutorial.


boundaryField
{
top
{
type fixedValue;
value uniform (0 0 0);
}
bottom
{
type fixedValue;
value uniform (0 0 0);
}
left
{
type fixedValue;
value uniform (0 0 0);
}
right
{
type fixedValue;
value uniform (0 0 0);
}
frontAndBack
{
type empty;
}
}

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:

Contents of the initial temperature file (0/T) in the heatedCavity tutorial.


dimensions [0 0 0 1 0 0 0];
internalField uniform 273;
boundaryField
{
top
{
type zeroGradient;
}
bottom
{
type zeroGradient;
}
left
{
type fixedValue;
value uniform 273;
}
right
{
type fixedValue;
value uniform 373;
}
frontAndBack
{
type empty;
}
}

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

Contents of the gravity definition file (constant/g) in the heatedCavity tutorial.


/*--------------------------------*- 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 -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

The Q2DmhdFoam solver

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.

4.1 Implementation of the Q2DmhdFoam solver


This section will show how to implement the Q2DmhdFoam modifying the boussinesqBuoyantFoam.
After sourcing our FOAM distribution, we go to the installation directory of the foam-extend
installation folder and copy the boussinesqBuoyantFoam solver files into the user directory:

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

after what we obtain the following output:

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.

sed -i s/boussinesqBuoyantFoam/Q2DmhdFoam/g Q2DmhdFoam.C


sed -i s/boussinesqBuoyantFoam/Q2DmhdFoam/g Make/files

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:

Description section of the main C file.


/*---------------------------------------------------------------------------*\
========= |
\\ / 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
...

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

New description section of the main C file.


/*---------------------------------------------------------------------------*\
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

\*---------------------------------------------------------------------------*/

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:

Raw readTrasportProperties.H file.


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
(
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:

Modification in reading the kinematic viscosity in readTrasportProperties.H file.


dimensionedScalar nu
(
transportProperties.lookup("nu")
);

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.

Code added to readTrasportProperties.H.


dimensionedScalar Cp
(
transportProperties.lookup("Cp")
);

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.

Code added to createFields.H


Info<< "Reading field B\n" << endl;
volScalarField B
(
IOobject
(
"B",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);

Info<< "Calculating field sourceT\n" << endl;


// Infer the sourceT BCs from the pressure (set all to zeroGradient)
wordList sourceTBCTypes
(
p.boundaryField().size(),
zeroGradientFvPatchScalarField::typeName
);
volScalarField y = mesh.C().component(vector::Y);
if (coord == 1)
{
y = mesh.C().component(vector::X);
}
if (coord == 2)
{
y = mesh.C().component(vector::Y);
}
if (coord == 3)
{
y = mesh.C().component(vector::Z);
}
volScalarField sourceT
(
IOobject
(
"sourceT",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
q0*exp(- (y/a + 1) * m),
sourceTBCTypes
);

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.

Modifying the main file

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.

Momentum equation in Q2DmhdFoam.C. Added code in red.


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));

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.

Energy equation in Q2DmhdFoam.C. Added code in red.


// Solve energy equation
solve
(
fvm::ddt(T)
+ fvm::div(phi, T)
- fvm::laplacian(DT, T)
- sourceT/(rho0*Cp)
);

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"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

int main(int argc, char *argv[])


{

# 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"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Info<< "\nStarting time loop\n" << endl;

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.

4.2 Using the Q2DmhdFoam solver


4.2.1 Configuring the first case
The first tutorial case will come from the combination of the mhdFoam tutorial: the hartmann tutorial,
and the boussinesqBuoyantFoam case: the heatedCavity case, tuned to fit the new solver.
First, we copy the heatedCavity tutorial in our working directory (after sourcing our foam-extend
distribution). We name it liquidMetalChannel.
cp -r $FOAM_TUTORIALS/heatTransfer/boussinesqBuoyantFoam/heatedCavity/ \
liquidMetalChannel
cd liquidMetalChannel
This tutorial provides for the temperature and buoyancy features that we want but still lacks
the magnetic field and some electromagnetic parameters. Also, the geometry is that of the cavity
case, but we want a 2D channel to be simulated, similar to that of the hartmann case. We first copy
the blockMeshDict file of that tutorial to substitute our current one and perform blockMesh.
cp -r \
$FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann/constant/polyMesh/blockMeshDict \
constant/polyMesh
blockMesh

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

Initial conditions in the temperature 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 volScalarField;
object T;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

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

transportProperties file after modifications


/*--------------------------------*- 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 transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

rho0 rho0 [1 -3 0 0 0 0 0] 1.0;


nu nu [0 2 -1 0 0 0 0] 1.0;
T0 T0 [0 0 0 1 0 0 0] 0.0;
Cp Cp [0 2 -2 -1 0 0 0] 1;
k k [1 1 -3 -1 0 0 0] 0.0001;
beta beta [0 0 0 -1 0 0 0] 1e-3;
a a [0 1 0 0 0 0 0] 1;
b b [0 1 0 0 0 0 0] 1;
sigma sigma [-1 -3 3 0 0 2 0] 1;
q0 q0 [1 -1 -3 0 0 0 0] 0;
m m [0 0 0 0 0 0 0 ] 1;
coord 2; //X_axis:1, Y_axis:2, Z_axis:3

// ************************************************************************* //

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

sed -i s/"(mu|rho0)"/nu/g system/fvSchemes

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.

4.2.2 Observing buoyancy effects with Q2DmhdFoam


As stated before, one of the features of the Q2DmhdFoam solver is the ability to simulate buoyancy
effects caused by temperature differences in some magnetohydrodynamic conditions. This section
will show how to modify the liquidMetalChannel case (see Section 4.2.1) into a new case called
liquidMetalChannelHeated configured to reproduce heat deposition.
First, after sourcing our FOAM distribution, we will copy the liquidMetalChannel case.

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

Figure 4.1: Influence of the magnetic field in the velocity profile.

0/T file for the liquidMetalChannelHeated case.


dimensions [0 0 0 1 0 0 0];
internalField uniform 773;
boundaryField
{
inlet
{
type fixedValue;
value uniform 773;
}
outlet
{
type zeroGradient;
}
upperWall
{
type zeroGradient;
}
lowerWall
{
type zeroGradient;
}
frontAndBack
{
type empty;
}
}

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

constant/transportProperties file for the liquidMetalChannelHeated case. Modified code in


red.
/*--------------------------------*- 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 transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

rho0 rho0 [1 -3 0 0 0 0 0] 1.0;


nu nu [0 2 -1 0 0 0 0] 1.0;
T0 T0 [0 0 0 1 0 0 0] 773;
Cp Cp [0 2 -2 -1 0 0 0] 1;
k k [1 1 -3 -1 0 0 0] 0.0001;
beta beta [0 0 0 -1 0 0 0] 1e-3;
a a [0 1 0 0 0 0 0] 1;
b b [0 1 0 0 0 0 0] 1;
sigma sigma [-1 -3 3 0 0 2 0] 1;
q0 q0 [1 -1 -3 0 0 0 0] 50;
m m [0 0 0 0 0 0 0 ] 1;
coord 2; //X_axis:1, Y_axis:2, Z_axis:3

// ************************************************************************* //

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:

constant/g file for the liquidMetalChannelHeated case.


/*--------------------------------*- 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 ( -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

system/controlDict file for the liquidMetalChannelHeated case.


/*--------------------------------*- 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 controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

...

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.

Figure 4.2: Visualization of the sourceT field along the channel.

The velocity profiles obtained in the liquidMetalChannel and liquidMetalChannelHeated


cases can be compared to see the influence of buoyancy (see Figure 4.3). It can be seen how, having
the same average velocity, the heated case accelerates its profile in the hot side and slows down the
cold side.

37
4.2. Using the Q2DmhdFoam solver Chapter 4. The Q2DmhdFoam solver

Figure 4.3: Comparison of heated and non-heated velocity fields.

38
Chapter 5

Validation and postprocessing

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:

ˆ Receives the conditions that parameterize the case to be simulated.

ˆ Calculates the proper mesh configuration based on the parameters (mainly the magnetic field).

ˆ Performs find and substitute tasks on the case-definition files.

ˆ Automatically meshes and runs the case.

ˆ Post-processes the output data to show the results of the validation concerning the analytical
solution.

5.1 Validation case


The case to benchmark [7] was proposed to study magnetohydrodynamic flows in vertical enclosures
under buoyant forces. This study supports the PbLi blanket European program for nuclear fusion, in
which lithium-lead alloys are used as the fuel breeder in fusion reactors. This blanket is distributed
along several ducts that can take about 10 meters of length at a flow rate of a few mm/s and it is
influenced by magnetic fields that can reach 10 T.
Specifically, Tagawa et al. consider in this example an infinitely long vertical square duct of
15 cm of side length in which there is no driving force but thermal stress applied through fixing
different temperatures in the walls. The flow is assumed to reach steady state and the magnetic
and temperature constraints are input using the Hartmann and Grashof numbers, respectively (see
Section 2.5).
The case we chose sets the heat flux perpendicular to the magnetic field—precisely the setup
that Q2DmhdFoam allows—, with Ha=100 and Gr=104 . We use the physical properties extracted
from PbLi databases [8, 9] to characterize the fluid (see table 5.1).
In order to analyze the case, the dimensionless vertical velocity, W and temperature, θ are defined
as
l
W =v (5.1)
ν
and
T − (Th + Tc )/2
θ= (5.2)
Th − Tc
where l, Tc and Th are the side lenght of the channel (l = 2a = 2b in case of a square duct) and the
cold and hot temperatures, respectively.

39
5.2. Validation procedure Chapter 5. Validation and postprocessing

Table 5.1: PbLi physical properties [8, 9].

ρ density 9720 kg/m3


σ electrical conductivity 763000 S/m
cp specific heat 189 J/kg· K
k thermal conductivity 22.36 W/m· K
β thermal expansion coef. 0.00012 1/K
ν kinematic viscosity 1.54 · 10−7 m2 /s

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.

5.2 Validation procedure


This section will review the steps followed to reproduce the case described in the previous section.
A Python script will be created to automate the process of case configuring, meshing, running and
post-processing. To this aim, first, we will show the steps for pre-configuring the case files.

5.2.1 Case configuring


Prior to executing the automation script, we wanted to configure the case files so that the script can
interact with them and change the main parameters affecting the simulation: geometry, physical
properties and field initial conditions. Physical properties will be used both by the script, for
meshing and validation purposes, and by the case files (e.g. transportProperties). Therefore, to
avoid duplicated values and for consistency, it would be a good idea to unite the source of these
values to one only place: the Python script, which would act as a master handler. This also happens
to automate the situation of running different cases, since the user only needs to change values at
one only place if he/she wants to make slight changes to the simulation case. Furthermore, it is
useful for having full control of the meshing process. In this case, the thin boundary layers need
special care and the definition of several blocks used by blockMesh. Configuring the blockMeshDict
file by hand can lead to several errors that are hard to track.
For this, we inserted tags along the case files following a specific format to make them easily
replaceable by code. Tags follow the following format: they start with an opening slash, /, followed
by the name (identifier) of the tag and end with a closing slash, /, e.g. /TAG_NAME/. The closing
and opening characters make the tags easy to be univocally found and replaced by the real value
used later in the simulation.
The usefulness of this approach will be seen along the configuration process. The files affected
by the use of tags are the initial field files U, T and B; the properties files transportProperties and
g; the blockMeshDict file and the sampling file sampleDict. We will start by copying one of the
prepared cases, the LiquidMetalChannelHeated case and we will call the new case baseCaseTagawa:

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

Contents of the 0/U initial field for the tagawa validation.


internalField uniform (/Ux/ 0 0);
boundaryField
{
inlet
{
type fixedValue;
value uniform (/Ux/ 0 0);
}
outlet
{
type fixedValue;
value uniform (/Ux/ 0 0);
}
lowerWall
{
type fixedValue;
value uniform (0 0 0);
}
upperWall
{
type fixedValue;
value uniform (0 0 0);
}
frontAndBack
{
type empty;
}
}

Contents of the 0/T initial field for the tagawa validation.


internalField uniform /T0/;
boundaryField
{
inlet
{
type zeroGradient;
}
outlet
{
type zeroGradient;
}
upperWall
{
type fixedValue;
value uniform /Tc/;
}
lowerWall
{
type fixedValue;
value uniform /Th/;
}
frontAndBack
{
type empty;
}
}

41
5.2. Validation procedure Chapter 5. Validation and postprocessing

Contents of the 0/B initial field for the tagawa validation.


internalField uniform /B/;

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.

Contents of the constant/transportProperties file for the tagawa validation.


rho0 rho0 [1 -3 0 0 0 0 0] /rho0/;

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/;

beta beta [0 0 0 -1 0 0 0] /beta/;

a a [0 1 0 0 0 0 0] /a/;

b b [0 1 0 0 0 0 0] /b/;

sigma sigma [-1 -3 3 0 0 2 0] /sigma/;

q0 q0 [1 -1 -3 0 0 0 0] /q0/;

m m [0 0 0 0 0 0 0 ] /m/;

coord 2; //X_axis:1, Y_axis:2, Z_axis:3

Contents of the constant/g file for the tagawa validation.


dimensions [0 1 -2 0 0 0 0];
value (/g/ 0 0 );

42
5.2. Validation procedure Chapter 5. Validation and postprocessing

The blockMeshDict tagged content is shown next.

Contents of the system/blockMeshDict file for the tagawa validation.


x /Lx/;
y /LyBulk/;
yNeg /LyNegBulk/;
yBL /LyBL/;
yNegBL /LyNegBL/;

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

Table 5.2: Explanation of mesh-related tags.

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

Figure 5.1: Example of blocks set in blockMeshDict.

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

meshAndGo.py file. Part III.


# Define directory names
base_dir = 'baseCaseTagawa'
curr_dir = 'tagawa'
# Create new case directory
sp.call('cp -r ' + base_dir + ' ' + curr_dir, shell=True)

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:

meshAndGo.py file. Part IV.


######################
### 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))

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.

meshAndGo.py file. Part V.


######################
### 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))

# This is HALF the length of the bulk


l_bulk = tag_dict['a'] - l_side
N_bulk, G_bulk, _ = utils.lenCminC2C(l_bulk, cmax)
print('HALF BULK')
print('bulk half length = {}'.format(l_bulk))
print('N = {}'.format(N_bulk))
print('G = {}'.format(G_bulk))

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.

meshAndGo.py file. Part VI.


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)
# Replace all tags
utils.replaceTags(tag_dict, curr_dir)

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.

meshAndGo.py file. Part VII.


######################
### 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)

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.

meshAndGo.py file. Part VIII.


######################
### 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')

48
5.3. Results Chapter 5. Validation and postprocessing

meshAndGo.py file. Part IX.


# 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)

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:

Replacing /a/ tag in tagawa/system/sampleDict file. Value: 0.075.


Replacing /LxHalf/ tag in tagawa/system/sampleDict file. Value: 7.5.
Replacing /Lx/ tag in tagawa/system/blockMeshDict file. Value: 15.0.
Replacing /LyBulk/ tag in tagawa/system/blockMeshDict file. Value: 0.075.
Replacing /LyBL/ tag in tagawa/system/blockMeshDict file. Value: 0.0675.
Replacing /LyNegBulk/ tag in tagawa/system/blockMeshDict file. Value: -0.075.
Replacing /LyNegBL/ tag in tagawa/system/blockMeshDict file. Value: -0.0675.
Replacing /Nx/ tag in tagawa/system/blockMeshDict file. Value: 100.
Replacing /NyBulk/ tag in tagawa/system/blockMeshDict file. Value: 27.
Replacing /NyBL/ tag in tagawa/system/blockMeshDict file. Value: 25.
Replacing /GyBulk/ tag in tagawa/system/blockMeshDict file. Value: 13.017
Replacing /GyBulkInv/ tag in tagawa/system/blockMeshDict file. Value: 0.07682
Replacing /GyBL/ tag in tagawa/system/blockMeshDict file. Value: 3.2251
Replacing /GyBLinv/ tag in tagawa/system/blockMeshDict file. Value: 0.31007
Replacing /Ux/ tag in tagawa/0/U file. Value: 0.0.
Replacing /T0/ tag in tagawa/0/T file. Value: 0.0.
Replacing /Th/ tag in tagawa/0/T file. Value: 2.9846088018021425e-05.
Replacing /Tc/ tag in tagawa/0/T file. Value: -2.9846088018021425e-05.
Replacing /B/ tag in tagawa/0/B file. Value: 0.029528403368698886.
Replacing /T0/ tag in tagawa/constant/transportProperties file. Value: 0.0.
Replacing /a/ tag in tagawa/constant/transportProperties file. Value: 0.075.
Replacing /b/ tag in tagawa/constant/transportProperties file. Value: 0.075.
Replacing /q0/ tag in tagawa/constant/transportProperties file. Value: 0.

49
5.3. Results Chapter 5. Validation and postprocessing

Replacing /m/ tag in tagawa/constant/transportProperties file. Value: 1.


Replacing /rho0/ tag in tagawa/constant/transportProperties file. Value: 9720.
Replacing /nu/ tag in tagawa/constant/transportProperties file. Value: 1.54e-07.
Replacing /Cp/ tag in tagawa/constant/transportProperties file. Value: 189.
Replacing /k/ tag in tagawa/constant/transportProperties file. Value: 22.36.
Replacing /beta/ tag in tagawa/constant/transportProperties file. Value: 0.00012.
Replacing /sigma/ tag in tagawa/constant/transportProperties file. Value: 763000.
Replacing /g/ tag in tagawa/constant/g file. Value: -9.81.

and, in a few seconds, a plot with the resulting velocity results should pop up and show something
similar to Figure 5.2.

15 Bulk analytical solution


Q2DmhdFoam

10

5
Dimensionless velocity, W

−5

−10

−15

−0.4 −0.2 0.0 0.2 0.4


Dimensionless length, X = x/l

Figure 5.2: Results of the validation by the Tagawa case.

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?

3. What are the disadvantages of the Q2DmhdFoam?


4. How can you take advantage of scripting for running several FOAM cases sequentially?

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.

foam-extend is free software: you can redistribute it and/or modify it


under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

foam-extend is distributed in the hope that it will be useful, but


WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

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"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

int main(int argc, char *argv[])


{

# 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"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Info<< "\nStarting time loop\n" << endl;

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));

// --- PISO loop

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();
}

// Solve energy equation


solve
(
fvm::ddt(T)
+ fvm::div(phi, T)
- fvm::laplacian(DT, T)
- sourceT/(rho0*Cp)
);

rho = rho0*(scalar(1) - beta*(T - T0));

runTime.write();

Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"


<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}

Info<< "End\n" << endl;

return(0);
}

// ************************************************************************* //

createFields.H
Info<< "Reading field p\n" << endl;
volScalarField p
(
IOobject
(
"p",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);

Info<< "Reading field T\n" << endl;


volScalarField T
(
IOobject
(
"T",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);

Info<< "Reading field U\n" << endl;


volVectorField U
(
IOobject
(
"U",
runTime.timeName(),

55
A.1. Q2DmhdFoam Appendix A. Developed codes

mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);

# include "createPhi.H"

Info<< "Reading field B\n" << endl;


volScalarField B
(
IOobject
(
"B",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);

label pRefCell = 0;
scalar pRefValue = 0.0;
setRefCell(p, piso.dict(), pRefCell, pRefValue);
mesh.schemesDict().setFluxRequired(p.name());

Info<< "Reading/calculating field rho\n" << endl;


volScalarField rho
(
IOobject
(
"rho",
runTime.timeName(),
mesh,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
rho0*(scalar(1) - beta*(T - T0))
);

Info<< "Calculating field sourceT\n" << endl;


// Infer the sourceT BCs from the pressure (set all to zeroGradient)
wordList sourceTBCTypes
(
p.boundaryField().size(),
zeroGradientFvPatchScalarField::typeName
);
volScalarField y = mesh.C().component(vector::Y);
if (coord == 1)
{
y = mesh.C().component(vector::X);
}
if (coord == 2)
{
y = mesh.C().component(vector::Y);
}
if (coord == 3)
{
y = mesh.C().component(vector::Z);
}
volScalarField sourceT
(
IOobject
(

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"))
);

A.2 Python script

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]

# 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
}

# Update main dictionary with physical properties


phys_dict = {
'rho0' : 9720,
'nu' : 1.54e-7,
'Cp' : 189,
'k' : 22.36,
'beta' : 1.2e-4,
'sigma' : 763000
}
tag_dict.update(phys_dict)

58
A.2. Python script Appendix A. Developed codes

# Define directory names


base_dir = 'baseCaseTagawa'
curr_dir = 'tagawa'
# Create new case directory
sp.call('cp -r ' + base_dir + ' ' + curr_dir, shell=True)

######################
### 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))

# This is HALF the length of the bulk


l_bulk = tag_dict['a'] - l_side
N_bulk, G_bulk, _ = utils.lenCminC2C(l_bulk, cmax)
print('HALF BULK')
print('bulk half length = {}'.format(l_bulk))
print('N = {}'.format(N_bulk))
print('G = {}'.format(G_bulk))

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

# Replace all tags


utils.replaceTags(tag_dict, curr_dir)

######################
### 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

foam-extend, 13, 18, 24, 26, 30 OpenFOAM, 12, 13

mhdFoam, 1, 12, 20, 21, 24, 27, 28, 30 Q2DmhdFoam, 52

61

You might also like