 ## Heat Transfer Demo 2: A 2-D transient diffusion code

This code is developed to solve 2-D transient (time dependent) heat transfer problems. We use here an alternative to the presentation of the previous demo code. More specifically, we show how to perform all important phases of a time dependent finite element code.

• As usual, the program starts by including the header file OFELI.h that itself includes all kernel class definitions, then we include thermal dedicated classes described in Therm.h. We also declare the namespace to simplify the code writing:

 ```#include "OFELI.h" #include "Therm.h" using namespace OFELI; ```

• We construct an instance of class IPF to manage project data. We extract useful information from this instance: The maximal time, the time step, a flag for saving results and another for controlling output.

 ``` IPF data("ttd2 - 1.1",argv); theFinalTime = data.getMaxTime(); theTimeStep = data.getTimeStep(); int save_flag = data.getSave(); int verbose = data.getVerbose();```

• We instantiate class IOField to store the solution for plotting:

 ` IOField pf(data.getPlotFile(),IOField::OUT);`

• We now define the Mesh instance and the matrix (class SkSMatrix<double> handles skyline symmetric storage). We next instantiate vectors b and u that will contain respectively the right-hand side and the solution.

 ``` Mesh ms(data.getMeshFile()); SkSMatrix A(ms); Vect b(ms), u(ms); ```

• The initial solution is given through the class Prescription.

 ``` Prescription pr(ms,data.getDataFile()); pr.get(INITIAL_FIELD,u);```

• Boundary conditions and source vector will also be defined in the same way, but since all these properties are time dependent, we will do this each time step. For now, we just instantiate these vectors and define a NodeVect instance.

 ` Vect bc(ms), body_f(ms), bound_f(ms);`

• We start the time step loop using the macro TimeLoop:

 ``` TimeLoop { b = 0;```

• For the current time step, we get (Dirichlet) boundary conditions, sources and fluxes (Neumann boundary conditions):

 ``` pr.get(BOUNDARY_CONDITION,bc,time); pr.get(SOURCE,body_f,time); pr.get(FLUX,bound_f,time);```

• We define a loop over mesh elements to fill element arrays. We use here the macro MeshElements that stands for a shorthand of the element loop. It uses the mesh instance and gives a value to the global pointer theElement to class Element:

 ``` MeshElements(ms) { ```

• For each element, we first define an instance of class DC2DT3 which handles diffusion-convection problems in 2-D domains using 3-node triangular finite elements (P1 elements). We make use of the constructor for time dependent problems, this one involving the solution at previous time step and the current value of time. We then add the (lumped) capacity contribution to the element matrix and right-hand side. Note that this contribution is multiplied by the inverse of the time step. We also add a contribution of the diffusion matrix. All this corresponds to an implementation of the backward Euler scheme. We finally add the body right-hand side:

 ``` DC2DT3 eq(theElement,u,theTime); eq.LCapacity(double(1./theTimeStep)); eq.Diffusion(); eq.BodyRHS(body_f);```

• Once element arrays are computed, we assemble them to the global matrix and right-hand side. Note that since the matrix is computed and factorized only once, we avoid reassembling it.

 ``` if (step==1) eq.ElementAssembly(A); eq.ElementAssembly(b); }```

• When Neumann boundary conditions are concerned (fluxes), we have to add a loop over sides. Such a loop is very similar to element loops.

 ``` MeshSides(ms) { DC2DT3 eq(theSide,u,theTime); eq.BoundaryRHS(Vect(theSide,bound_f)); eq.SideAssembly(b); }```

• Once the linear system is constructed, we impose (Dirichlet) boundary conditions by a penalty technique. This is done by the member function Prescribe that belongs to all matrix classes. We then solve the linear system by factorization and backsubstitution. The obtained solution is contained in b and transferred to vector u.

 ``` A.Prescribe(b,bc,theStep-1); A.solve(b); u = b;```

• It remains now to store the solution in a file if the parameter save_flag enables it. The procedure it to store the solution each multiple of save_flag step.

 ``` u.setTime(theTime); if (theStep%save_flag == 0) pf.put(u); }```

Note that we have stored in the solution vector the time value, so that this one can be retrieved for plotting.

## An example

Let us run this program with the data presented in the following project file:

 ``` Finite Element Mesh of a beam January 1, 2010 R. Touzani proj-5x10.m proj.pl 0.01 1.0 0 0 1 -tanh(10)*(exp(t)-1) tanh(10)*(exp(t)-1) tanh(10*y)*(exp(t)+200*(exp(t)-1)/(cosh(10*y)*cosh(10*y))) ```

In summary, this file looks mainly like the one in the previous example. We show here in addition how to prescribe a boundary condition by an algebraic expression. The library is equipped with the expression parser fparser. We use here the variables x, y, z, and t for space and time variables.