This page contains some technical details of the benchmark Bestest. See this page for the complete description, and the results of this benchmark. The complete model can be found here.

1. From 2D to 3D

Previously, the application feelpp_hm_heat_moisture worked only for two-dimensional geometries. For the simulations we want to make for Bestest, we need to use a three-dimensional geometry.

The easiest way to do it is the build two separates programs : feelpp_hm_heat_moisture_2d and feelpp_hm_heat_moisture_3d. In the beginning, the mesh was declared in the code with

auto mesh = loadMesh( _mesh=new Mesh<Simplex<2>> );

the 2 standing for the dimension. To work in 3D, we just have to replace this 2 by a 3. The line is replaced in the code by

auto mesh = loadMesh( _mesh=new Mesh<Simplex<FEELPP_DIM>> );

The macro FEELPP_DIM is declared at the compilation with CMake with

feelpp_add_application(heat_moisture_3d SRCS hm_main.cpp hm_options.cpp DEFS FEELPP_DIM=3)

2. Resolution with Feel++

To solve such a problem with Feel++, we use product spaces. The space for heat in the walls is approximated by Xh_ = Pch<1> (polynomials of degree 1 on each element of the mesh), and the space for the heat in the room (which is constant) is approximated by Wh_ = Pch<0>. The space product is defined in Feel++ by the line

ps_ = product (Xh_, Wh_) ;

In the code (and therefore in the JSON file), the markers of the domains corresponding to the room (\(\Omega_r\)) in the description are named Air.

The principle of resolution of the variational problem is similar to was is done with a « simple » space, but we use here blockform2 and blockform1 (instead of form2 and form1) to set the bilinear and linear forms used.

In the code, the blockform2 is called bbf_. To set this form, we use the objects 0_c and 1_c, representing respectively the first and second row/column of the block-bilinear form.

To set the part of the variational problem corresponding to Xh_, we use bbf_( 0_c,0_c ), and on Wh_ it is bbf_( 1_c,1_c ).

It works the same way for the block-linear form blf_ : the set the member associated with Xh_ (respectively Wh_) we use blf_(0_c) (resp. blf_(1_c)).

The solve function will solve the bloc problem, and we just have to get the two separate solutions, for the wall, and the room :

void solve()
    auto T = this->ps_.element();
    this->bbf_.solve( _solution = T, _rhs = this->blf_ );
    T_  = T( 0_c );
    Ta_ = T( 1_c );

The mesh mesh_ from the geometry is divided into two meshes :

  • trace_mesh_ which corresponds to the submesh of mesh_ containing the borders between the room and the wall. The marker of those faces has to be "Air".

  • wall_mesh_ containing all the elements of the wall. Such mesh can be get with the complement of the room, which will be named Omega_room in the geometry (see here, on section 1.3 for more information about complement).

A distinction have to be done : for the previous cases (such as moisture-uptake), the coupling between the room and the wall mustn’t be taken. All the terms of the variationnal problem which are related to the air tranfer model are grouped in a if loop :

if ( this->mesh_->hasAnyMarker( { "Air" } ) ) { ... }

All the terms in this loop are the terms of the variational problem that are on \(\Gamma_i\), and on \(\Omega_r\).

Furthermore, if we are not on a case where we want to simulate in the room, we cannot let the bloc (1_c,1_c) of the bilinear form empty to avoid it, we just add an else statement to the if ( this→mesh_→hasAnyMarker( { "Air" } ) )

else {
    this->bbf_( 1_c, 1_c ) += integrate( _range = boundaryfaces( this->mesh() ), _expr = id( Ta_ ) * idt( Ta_ ) );
    this->blf_( 1_c ) += integrate( _range = boundaryfaces( this->mesh() ), _expr = idt( Ta_ ) );