Stokes equation

Stokes' equation is a good place to see the formulation and the assembly of various blocks in the system. As in the Poisson sample, it is optionnally solved as a non-linear problem.

The finite element type for the hydrostatic pressure P is given by degreeP. When positive, it uses a discontinuous finite element P0 or P1D. When negative, it uses a lagrange finite element with a degree equal to degreeU+degreeP. Hence degreeU=2 and degreeP=-1 means lagrange degree 2 for U and lagrange degree 1 for P.

/*
 *  nvi_Stokes__form__grid2.cpp
 *
 *      2D / cavity / stationnaire
 *
 */

#include "nvi_Stokes.h"
#include "nvi_Formulation__framework_01.h"

#include "navlib_math_flt.h"
#include <iostream>


namespace nvi::FormulationFrameworks
{
    struct UProblem__Stokes__0 : public Formulation__framework_01
    {
        struct parameters_t
        {
            bool newton = false;
            uint degreeU = 1;
            int  degreeP = 0;
            Expr nu = 1.;
        };
        UProblem__Stokes__0(Processor& proc, txt name, Mesh&& m, const parameters_t& pp) : Formulation__framework_01(proc,name,std::move(m))
        {
            auto U  = variable("U",2,pp.degreeU);
            auto P  = variable("P",  pp.degreeP);
            
            auto U_ = dual(U);
            auto P_ = dual(P);

            auto points = _points_ ();
            auto dx     = _dx_();
            
            auto x      = X (points);
            auto u      = U (points);
            auto p      = P (points);
            
            auto u_     = U_(points);
            auto p_     = P_(points);

            auto grad_u  = grad(U) (points);
            auto grad_p  = grad(P) (points);
            
            auto grad_u_ = grad(U_)(points);
            
            auto  div_u  = trace(grad_u);
            
            const double pi = std::acos(-1.);

            const auto nu = scalar_of_X(pp.nu,x);
            
            auto  I  = identity_matrix();
            auto _I_ = Tensor::_I_(dim);
                        
            if (pp.newton)
            {
                auto formU  = form1( dx * (nu*grad_u + p*I), grad_u_);
                auto formP  = form1( dx * div_u,             p_);

                assemble_in_vector(U,formU);
                assemble_in_vector(P,formP);
            }
            auto formUU = form2( dx * nu*_I_,           grad_u_);
            auto formUP = form2( dx * I,      grad_u_,  p_);
            
            assemble_in_matrix(U,formUU);
            assemble_in_matrix(U,P,formUP,symmetric_counter_part_);
            
                        
            add_Dirichlet("Dirichlet",U,{"X=0"});
            add_Dirichlet("Dirichlet",U,{"X=1"});
            add_Dirichlet("Dirichlet",U,{"Y=0 internal"});
            add_Dirichlet("Dirichlet",U,{"Y=1 internal"},{sin(_x*pi),Expr(0.)});
        }
    };
}


void nvi::Stokes_0_grid2(txt output_dir)
{
    text name = __FUNCTION__;
    
    using namespace SpaceDiscretisation;
    using namespace FormulationFrameworks;

    auto processor = Processor__get (name,output_dir);
    
    const bool newton = true;
    const uint degreeX =  2;
    const uint degreeU =  2;
    const  int degreeP = -1;
    
    auto pb = UProblem__Stokes__0(processor,name,Mesh(processor,Grid2(50,51,degreeX)),{
        .newton  = newton,
        .degreeU = degreeU,
        .degreeP = degreeP,
        .nu = 1.
    });
    
    if (newton)
    {
        pb.newton_options.number_of_iterations = 5;
    
        pb.solve();
    }
    else
    {
        pb.line_solve(-1);
    }
    
    pb.save();
    
}

Results

../_images/Stokes-cavity.png

Log file

1 - Creating variable U: [2], degree=2
2 - Creating variable P: [], degree=2
3 - Building
.   1 - Identifying unknown variables
.   2 - Building system
.   .   1 - Vector formulations
.   .   2 - Vector formulations
.   .   3 - Matrix formulations
.   .   4 - Matrix formulations
.   .   5 - Dirichlet conditions
.   .   6 - Dirichlet conditions
.   .   7 - Dirichlet conditions
.   .   8 - Dirichlet conditions
3   2 * Building system: logs: 0, time: 3.12 ms (cpu: 40 ms)
3 * Building: logs: 0, time: 3.2 ms (cpu: 40 ms)
4 - SparseSystem instantiation
 >> symmetry_respect: 1; hermitian_kind 3
$chrono SparseSystem_instantiation: 45 ms (cpu: 540 ms)
5 - Newton initialization
6 - Newton iterations Time[1] = 1

===========================================================
           NEWTON : ITERATION 1
===========================================================
|| matrix || = 5.69 619.404
|| rhsU || = 0 0
|| rhsL1 || = 0 0
|| rhsL2 || = 0 0
|| rhsL3 || = 0 0
|| rhsL4 || = 0 0
|| rhsL5 || = 1 7.07107
|| rhsL || = 1 7.07107
|| lhsU || = 1 21.863
|| lhsL1 || = 30.1026 378.52
|| lhsL2 || = 0.25348 0.721822
|| lhsL3 || = 0.430692 1.21561
|| lhsL4 || = 0.0972815 0.715306
|| lhsL5 || = 0.39603 1.24585
|| lhsL || = 30.1026 378.526

---------------- ITERATION 1 TIMES ----------------------
$chrono assembly: 5.18 ms (cpu: 50 ms)
$chrono analysis: 123 ms (cpu: 1.64 s)
$chrono factorisation: 13.4 ms (cpu: 170 ms)
$chrono line_solve: 6.05 ms (cpu: 80 ms)


$chrono Newton iteration: 149 ms (cpu: 1.96 s)

===========================================================
           NEWTON : ITERATION 2
===========================================================
|| rhsU || = 1.60288e-14 9.81959e-14
|| rhsL1 || = 7.81194e-16 7.82513e-16
|| rhsL2 || = 5.67512e-21 2.0664e-20
|| rhsL3 || = 7.59224e-21 1.99168e-20
|| rhsL4 || = 5.31928e-21 1.69967e-20
|| rhsL5 || = 7.24798e-21 1.9146e-20
|| rhsL || = 9.81959e-14 7.82513e-16
|| lhsU || = 2.92218e-15 1.13574e-13
|| lhsL1 || = 0.00665125 0.335872
|| lhsL2 || = 8.69444e-05 0.000694223
|| lhsL3 || = 8.69444e-05 0.000694223
|| lhsL4 || = 8.86833e-05 0.0006997
|| lhsL5 || = 8.86833e-05 0.0006997
|| lhsL || = 0.00665125 0.335875
lhsU / lhsU0 = 2.92218e-15
lhsL / lhsL0 = 0.000220953

---------------- ITERATION 2 TIMES ----------------------
$chrono assembly_rhs: 1.35 ms (cpu: 20 ms)
$chrono line_solve: 4.75 ms (cpu: 70 ms)


$chrono Newton iteration: 7.2 ms (cpu: 100 ms)

===========================================================
===========================================================


===========================================================
===========================================================

===========================================================
  ***     Newton convergence in 2 iterations. STOP.    *** 
===========================================================

===========================================================
===========================================================

$chrono assembly <mean>: 5.18 ms (cpu: 50 ms)
$chrono assembly_rhs <mean>: 1.35 ms (cpu: 20 ms)
$chrono analysis <mean>: 123 ms (cpu: 1.64 s)
$chrono factorisation <mean>: 13.4 ms (cpu: 170 ms)
$chrono line_solve <mean>: 5.4 ms (cpu: 70 ms)
$chrono update <mean>: 227 us (cpu: 10 ms)
$chrono Newton iteration <mean>: 78 ms (cpu: 1.03 s)
7 - Writing mesh solution: Stokes_0_grid2