- When using the LinearOperator, the function vmult() is used when solving the system with a GMRES-solver (or similar). Does the same hold up for the MatrixFree-framework?
- If the above is correct: In each GMRES-iteration I have to calculate the residual of my equation, once for the current solution and once for the current solution + a small step. At the moment I calculate the residual by summing the terms into my residual vector, and then distributing the values while setting the boundary condition to 0. If I understand it correctly, that happens as soon as I call phi.distribute_local_to_global(dst), with phi a FEEvaluation-element.
- This means that I first have to assemble the residual vector, then distribute it, and then can use the vmult-function. Is that correct, or do I have to use another approach?
LinearOperator<LinearAlgebraTrilinos::MPI::Vector> jacobian_operator;
jacobian_operator.vmult = [&](LinearAlgebraTrilinos::MPI::Vector &dst, const LinearAlgebraTrilinos::MPI::Vector &src){
local_src = src;
extended_src = src;
local_solution = present_solution;
double epsilon = 1e-6;
if(local_src.l2_norm() != 0){
epsilon = sqrt((1 + local_solution.l2_norm()) * 1e-16) / local_src.l2_norm();
};
forward_eps_solution = present_solution;
backward_eps_solution = present_solution;
extended_src *= epsilon;
forward_eps_solution += extended_src;
backward_eps_solution -= extended_src;
compute_residual(backward_eps_solution, cur_residual);
compute_residual(forward_eps_solution, eps_residual);
eps_residual -= cur_residual;
eps_residual /= (2 * epsilon);
dst.reinit(locally_owned_dofs,
mpi_communicator);
dst = eps_residual;
};
My aim is to implement the jacobian approximation, i.e. (if F(u) = 0 is the function to solve) I wanted to implementdst = (F(current_solution + epsilon * src) - F(current_solution))/epsilon.In my LinearOperator, my code is
LinearOperator<LinearAlgebraTrilinos::MPI::Vector> jacobian_operator;
jacobian_operator.vmult = [&](LinearAlgebraTrilinos::MPI::Vector &dst, const LinearAlgebraTrilinos::MPI::Vector &src){
local_src = src;
extended_src = src;
local_solution = present_solution;
double epsilon = 1e-6;
if(local_src.l2_norm() != 0){
epsilon = sqrt((1 + local_solution.l2_norm()) * 1e-16) / local_src.l2_norm();
};
forward_eps_solution = present_solution;
backward_eps_solution = present_solution;
extended_src *= epsilon;
forward_eps_solution += extended_src;
backward_eps_solution -= extended_src;
compute_residual(backward_eps_solution, cur_residual);
compute_residual(forward_eps_solution, eps_residual);
eps_residual -= cur_residual;
eps_residual /= (2 * epsilon);
dst.reinit(locally_owned_dofs,
mpi_communicator);
dst = eps_residual;
};Is the same/similar possible for the matrix-free-approach?
No, that code is the vmult-call I am using in my LinearOperator (and is used directly in my solve()-call). The calculate_residual()-function is similar to the function in step-15, with the difference, that I do not provide alpha, but the vector, and return the calculated residual value.
Thus, as far as I could understand, I have to do the following in the matrix-free cell loop:On the other hand, would it be sufficient to unroll the residual-calculation, i.e. if the residual is F(u) = nabla^2 u + f, to write (in the cell-loop): (nabla^2(u + eps*src) + f - nabla^2u - f)/epsilon? Or would that lead to wrong results?
- Calculate residual of the current solution
- Calculate residual of the current solution + epsilon * src
- Calculate dst, and return it
Maxi,No, that code is the vmult-call I am using in my LinearOperator (and is used directly in my solve()-call). The calculate_residual()-function is similar to the function in step-15, with the difference, that I do not provide alpha, but the vector, and return the calculated residual value.So this is where your cell loop currently lives and that can be represented by a matrix-vector product. :-)Thus, as far as I could understand, I have to do the following in the matrix-free cell loop:On the other hand, would it be sufficient to unroll the residual-calculation, i.e. if the residual is F(u) = nabla^2 u + f, to write (in the cell-loop): (nabla^2(u + eps*src) + f - nabla^2u - f)/epsilon? Or would that lead to wrong results?
- Calculate residual of the current solution
- Calculate residual of the current solution + epsilon * src
- Calculate dst, and return it
It is sufficient to only change compute_diagonal() to use the MatrixFree framework. Passing multiple vectors at once might be a little bit more difficult to implement.
Currently, you residual seems to depend linearly on u. In that case, the difference does not depend on u at all.
Best,Daniel
On the other hand, would it be sufficient to unroll the residual-calculation, i.e. if the residual is F(u) = nabla^2 u + f, to write (in the cell-loop): (nabla^2(u + eps*src) + f - nabla^2u - f)/epsilon? Or would that lead to wrong results?It is sufficient to only change compute_diagonal() to use the MatrixFree framework. Passing multiple vectors at once might be a little bit more difficult to implement.Could you elaborate on that further (changing the diagonal value)?
Is there then a way to use LinearOperator as Input for a preconditioner? Else I still have to form the full system matrix (which I would like to avoid).