1. Bilinear and Linears Forms
We consider in this section bilinear and linear forms \(a: X_h \times X_h \rightarrow \mathbb{R}\) and \(\ell: X_h \rightarrow \mathbb{R}.\)
We suppose in this section that you know how to define your Mesh and your function spaces. You may need integration tools too, see Integrals.
There are Feel++ tools you need to create linear and bilinear forms in order to solve variational formulation.
from now on, u denotes an element from your trial function
space (unknown function) and v an element from your test function
space
|
1.1. Building Forms
1.1.1. Using form1
To construct a linear form \ell: X_h \rightarrow \mathbb{R}, proceed as follows
auto mesh = ...;
// build a P1/Q1 approximation space
auto Xh = Pch<1>( mesh );
auto l = form1(_test=Xh);
Name |
Parameter |
Description |
Status |
|
function space e.g. |
define test function space |
Required |
Here are some examples taken from the Feel++ tutorial.
From mylaplacian.cpp
// right hand side
auto l = form1( _test=Vh );
l = integrate(_range=elements(mesh), _expr=id(v));
From myadvection.cpp
// right hand side
auto l = form1( _test=Xh );
l+= integrate( _range=elements( mesh ), _expr=f*id( v ) );
The operators += and = are supported by linear and bilinear forms.
|
auto a1 = form2(_test=Xh,_trial=Xh);
auto a2 = form2(_test=Xh,_trial=Xh);
// operations on a2 ...
// check that they have the same type and
// copy matrix associated to a2 in a1
a1 = a2;
1.1.2. Using form2
To define a bilinear form a: X_h \times X_h \rightarrow \mathbb{R}, for example a(u,v)=\int_\Omega uv
Building form2
The free-function form2
allows you to simply define such a bilinear form using the Feel++ language:
// define function space
auto Xh = ...;
// define a : Xh x Xh -> R
auto a = form2(_trial=Xh, _test=Xh );
// a(u,v) = \int_\Omega u v
a = integrate(_range=elements(mesh), _expr=idt(u)*id(v));
Name |
Parameter |
Description |
Status |
|
function space e.g. |
define test function space |
Required |
|
function space e.g. |
define trial function space |
Optional |
Here are some examples taken from the Feel++ tutorial
From mylaplacian.cpp
// left hand side
auto a = form2( _trial=Vh, _test=Vh );
a = integrate(_range=elements(mesh),
_expr=gradt(u)*trans(grad(v)) );
From mystokes.cpp
:
// left hand side
auto a = form2( _trial=Vh, _test=Vh );
a = integrate(_range=elements(mesh),
_expr=trace(gradt(u)*trans(grad(u))) );
a+= integrate(_range=elements(mesh),
_expr=-div(u)*idt(p)-divt(u)*id(p));
see note above on operators += and =
|
Solving variational formulations
Once you created your linear and bilinear forms you can use the solve()
member function of your bilinear form.
The following generic example solves: find u \in X_h \text{ such that } a(u,v)=l(v) \forall v \in X_h
auto Xh = ...; // function space
auto u = Xh->element();
auto a = form2(_test=Xh, _trial=Xh);
auto l = form1(_test=Xh);
a.solve(_solution=u, _rhs=l, _rebuild=false, _name="");
Name |
Parameter |
Description |
Status |
|
element of domain function space |
the solution |
Required |
|
linear form |
right hand side |
Required |
|
boolean(Default = |
rebuild the solver components |
Optional |
|
string(Default = "") |
name of the associated Backend |
Optional |
Here are some examples from the Feel++ tutorial.
laplacian.cpp
// solve the equation a(u,v) = l(v)
a.solve(_rhs=l,_solution=u);
Using on
for Dirichlet conditions
The function on()
allows you to add Dirichlet conditions to your bilinear form before using the solve
function.
The interface is as follows
on(_range=..., _rhs=..., _element=..., _expr=...);
Required Parameters:
-
_range
domain concerned by this condition (see Integrals ). -
_rhs
right hand side. The linear form. -
_element
element concerned. -
_expr
the condition.
This function is used with += operator.
Here are some examples from the Feel++ tutorial.
mylaplacian.cpp
// apply the boundary condition
a+=on(_range=boundaryfaces(mesh),
_rhs=l,
_element=u,
_expr=expr(soption("functions.alpha")) );
There we add the condition: u = 0 \text{ on }\;\partial\Omega \;.
mystokes.cpp
a+=on(_range=boundaryfaces(mesh), _rhs=l, _element=u,
_expr=expr<2,1,5>(u_exact,syms));
You can also apply boundary conditions per component:
a+=on(_range=markedfaces(mesh,"top"),
_element=u[Component::Y],
_rhs=l,
_expr=cst(0.))
The notation u[Component:Y]
allows to access the Y
component of
u
. Component::X
and Component::Z
are respectively the X
and
Z
components.