>
> If the reference solution is 0, you can't see if you are missing a
> constant factor in your equation even when the rate of convergence looks
> correct.
>
I understand thank you !
> Yes, but then you also have to be careful with the boundary conditions. If
> you have an analytical solution with homogeneous Dirichlet boundary
> conditions for \phi,
> I would definitely try that first.
>
It already has homogeneous Dirichlet boundary conditions. \phi is set to 0
at the boundaries as well as all the other variables (u, v, P).
> The ansatz space is the space spanned by the basis functions you are using
> for your solution variables. In case the mapping from the reference cell to
> the
> real cell is affine and you use polynomial base functions (on the
> reference element), the ansatz space is polynomial as well. Then, it is
> easier to manufacture
> a solution that is contained in the ansatz space.
>
I'm not sure to understand how to manufacture a solution for my problem. I
have read step 7 a few times and I understand but for a coupled system like
mine, I don't see how to do it.
Should I choose a solution with u and v that already respect the
icompressibility equation ?
Should I keep the same phi or change it for another one ?
Should I keep the same boundary conditions (everything = 0) on the sides ?
>From the look of it, the problem comes from the stokes equation. In my
simple case described above, the problem in phi is just a poisson equation
and I checked that the solution is the correct one (with a good convergence
rate).
I also completely erased my assembly of the stokes problem and re-wrote it.
It did not change a thing.
By the way, i'm now confident that the problem comes from my dealii code
and not from my mathematica code. I have implemented the same code using
Fenics, the python library, and it gives the exact same results as the
mathematica code. I used the same weak formulation in both the dealii and
fenics codes.
Fenics and Mathematica use triangles for a mesh and Dealii use squares.
Could this cause a difference in the solution, especially knowing that i'm
working on a sphere ? I'm currently comparing the same equations on a
square mesh. We will see how it goes.
I'm joining a cpp file with the parts of the code that only correspond to
the stokes problem. I pretty much used the same format as in the tutorial
so it will look familiar to anyone that read or wrote them.
Will send another e-mail in the afternoon after I studied the problem on a
square mesh.
Thanks again to you Daniel for taking the time to help me, and for having
developed dealii which is by far the best FE solver for complex problems I
have used so far.
--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see
https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups
"deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/dealii/7b2ed826-bf59-42e9-97bd-d523fd820c26%40googlegroups.com.
//Définition de la classe
Elfe::Elfe (
double n,
double s,
double A,
double a,
double X,
unsigned int cycle,
std::string basename):
n(n),
s(s),
A(A),
a(a),
X(X),
basename(basename),
cycle(cycle),
phi_fe (2),
phi_dof_handler (triangulation),
stokes_fe(FE_Q<2>(2), 2,
FE_Q<2>(1), 1),
stokes_dof_handler(triangulation)
{
}
void Elfe::stokes_setup_dofs ()
{ //Fonction qui setup les degree of freedom pour stokes
//On génère le dofhandler
stokes_dof_handler.distribute_dofs (stokes_fe);
//On réorganise les dofs pour mettre u, v, p
std::vector<unsigned int> block_component(3, 0);
block_component[2] = 1;
DoFRenumbering::component_wise (stokes_dof_handler, block_component);
std::vector<types::global_dof_index> dofs_per_block;
dofs_per_block.resize (2);
DoFTools::count_dofs_per_block (stokes_dof_handler, dofs_per_block, block_component);
unsigned int dof_u = dofs_per_block[0];
unsigned int dof_p = dofs_per_block[1];
//On génère les conditions aux bords
stokes_constraints.clear();
DoFTools::make_hanging_node_constraints(stokes_dof_handler, stokes_constraints);
VectorTools::interpolate_boundary_values(stokes_dof_handler,
0,
ZeroFunction<2>(3),
stokes_constraints
);
stokes_constraints.close();
//On crée le sparsity pattern
BlockDynamicSparsityPattern dsp (dofs_per_block, dofs_per_block);
DoFTools::make_sparsity_pattern (stokes_dof_handler, dsp, stokes_constraints, false);
stokes_sparsity_pattern.copy_from (dsp);
//On resize les objets à la bonne taille
stokes_system_matrix.reinit (stokes_sparsity_pattern);
stokes_solution.reinit (dofs_per_block);
stokes_system_rhs.reinit (dofs_per_block);
}
void Elfe::solve_stokes()
{ //Fonction qui résout le problème de Stokes
std::cout << BOLDBLUE << "\n Résolution Stokes " << RESET
<< std::endl;
//On assemble le système
stokes_assemble_system();
std::cout << BLUE << "Inversion" << RESET
<< std::endl;
// On l'inverse
SparseDirectUMFPACK A_direct;
A_direct.initialize(stokes_system_matrix);
A_direct.vmult(stokes_solution, stokes_system_rhs);
stokes_constraints.distribute(stokes_solution);
std::cout << "\x1b[A\x1b[A\x1b[A";
}
void Elfe::stokes_assemble_system ()
{ //Fonction qui assemble le problème de Stokes
std::cout << BLUE << "Assemblage Stokes " << RESET
<< std::endl;
//On réinitialise la matrice et le rhs
stokes_system_matrix = 0;
stokes_system_rhs = 0;
//On charge de quoi extraire les valeurs
QGauss<2> quadrature_formula(4);
const unsigned int dofs_per_cell = stokes_fe.dofs_per_cell;
const unsigned int n_q_points = quadrature_formula.size();
std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
FullMatrix<double> local_matrix (dofs_per_cell, dofs_per_cell);
Vector<double> local_rhs (dofs_per_cell);
//Stokes values
FEValues<2> stokes_fe_values(stokes_fe, quadrature_formula,
update_values | update_gradients | update_JxW_values);
double u_i, v_i;
double u_i_x, u_i_y, v_i_x, v_i_y;
double u_j, v_j;
double u_j_x, u_j_y, v_j_x, v_j_y;
double P_i, P_j;
const FEValuesExtractors::Vector Velocities(0);
const FEValuesExtractors::Scalar Pressure(2);
//Phi values
FEValues<2> phi_fe_values(phi_fe, quadrature_formula,
update_values | update_gradients | update_JxW_values);
double phi, phi_x, phi_y;
double DX;
double philin = 2*pi*n;
double phiscale = 2*pi*s;
std::vector<Tensor<1, 2> > phi_solution_gradients(n_q_points);
std::vector<double> phi_solution_values(n_q_points);
//Il nous faut 2 cell iterator, un pour phi, un pour stokes
typename DoFHandler<2>::active_cell_iterator
stokes_cell = stokes_dof_handler.begin_active(),
stokes_endc = stokes_dof_handler.end();
typename DoFHandler<2>::active_cell_iterator
phi_cell = phi_dof_handler.begin_active();
for (; stokes_cell!=stokes_endc; ++stokes_cell, ++phi_cell)
{ //Pour chaque cell
stokes_fe_values.reinit(stokes_cell);
phi_fe_values.reinit (phi_cell);
local_matrix = 0;
local_rhs = 0;
//On récupère les valeurs pour les angles phis
phi_fe_values.get_function_values(phi_solution,
phi_solution_values);
phi_fe_values.get_function_gradients(phi_solution,
phi_solution_gradients);
for (unsigned int q=0; q<n_q_points; ++q)
{ //Pour chaque point de quadrature
DX = stokes_fe_values.JxW(q);
phi = phi_solution_values[q];
phi_x = phi_solution_gradients[q][0];
phi_y = phi_solution_gradients[q][1];
for (unsigned int i=0; i<dofs_per_cell; ++i)
{
u_i = stokes_fe_values[Velocities].value (i, q)[0];
v_i = stokes_fe_values[Velocities].value (i, q)[1];
u_i_x = stokes_fe_values[Velocities].gradient(i, q)[0][0];
u_i_y = stokes_fe_values[Velocities].gradient(i, q)[0][1];
v_i_x = stokes_fe_values[Velocities].gradient(i, q)[1][0];
v_i_y = stokes_fe_values[Velocities].gradient(i, q)[1][1];
P_i = stokes_fe_values[Pressure] .value (i, q);
local_rhs(i) += (
u_i*(
8*philin*phiscale*X
*(cos(2*phiscale*phi)*phi_x + sin(2*phiscale*phi)*phi_y)
+ 2*phiscale*phiscale*phi_x*(-4*philin/phiscale)
)
+ v_i*(
8*philin*phiscale*X
*(sin(2*phiscale*phi)*phi_x - cos(2*phiscale*phi)*phi_y)
+ 2*phiscale*phiscale*phi_y*(-4*philin/phiscale)
)
)*DX;
for (unsigned int j=0; j<dofs_per_cell; ++j)
{
u_j = stokes_fe_values[Velocities].value (j, q)[0];
v_j = stokes_fe_values[Velocities].value (j, q)[1];
u_j_x = stokes_fe_values[Velocities].gradient(j, q)[0][0];
u_j_y = stokes_fe_values[Velocities].gradient(j, q)[0][1];
v_j_x = stokes_fe_values[Velocities].gradient(j, q)[1][0];
v_j_y = stokes_fe_values[Velocities].gradient(j, q)[1][1];
P_j = stokes_fe_values[Pressure] .value (j, q);
local_matrix(i, j) += (
//Classical Stokes terms
- u_i_x*u_j_x - u_i_y*u_j_y - v_i_x*v_j_x - v_i_y*v_j_y
+ (u_i_x+v_i_y)*P_j
+ P_i*(u_j_x+v_j_y)
//Leslie Asymetrical terms
+ phiscale/a
*(v_i_x-u_i_y)
*(u_j*phi_x + v_j*phi_y + 1/2/phiscale*(u_j_y-v_j_x))
//Terme provenant du laplacien phi
-2*phiscale*phiscale/a
*(u_i*phi_x + v_i*phi_y)
*(u_j*phi_x + v_j*phi_y + 1/2/phiscale*(u_j_y-v_j_x))
)*DX;
}
}
}
stokes_cell->get_dof_indices (local_dof_indices);
//On applique les boundary conditions
stokes_constraints.distribute_local_to_global(local_matrix,
local_rhs,
local_dof_indices,
stokes_system_matrix,
stokes_system_rhs);
}
}
void Elfe::output_stokes () const
{ //Fonction qui sort u, v, P au format GPL
std::cout << BLUE << " Enregistrement de Stokes\n" << RESET;
std::stringstream stream;
stream << basename;
std::string fileName = stream.str();
DataOut<2> data_out;
data_out.attach_dof_handler (stokes_dof_handler);
data_out.add_data_vector (stokes_solution, "solution");
data_out.build_patches ();
std::ofstream output (fileName);
data_out.write_gnuplot (output);
}