crumb trail: > petsc-nonlinear > Nonlinear systems
Nonlinear system solving means finding the zero of a general nonlinear function, that is: \begin{equation} \mathop{?}_x\colon f(x)=0 \end{equation} with $f\colon \bbR^n-\bbR^n$. In the special case of a linear function, \begin{equation} f(x) = Ax-b, \end{equation} we solve this by any of the methods in chapter PETSc solvers .
The general case can be solved by a number of methods, foremost Newton's method , which iterates \begin{equation} x_{n+1} = x_n - F(x_n)\inv f(x_n) \end{equation} where $F$ is the Hessian $F_{ij}=\partial f_i/\partial x_j$.
You see that you need to specify two functions that are dependent on your specific problem: the objective function itself, and its Hessian.
crumb trail: > petsc-nonlinear > Nonlinear systems > Basic setup
The PETSc nonlinear solver object is of type SNES : `simple nonlinear equation solver'. As with linear solvers, we create this solver on a communicator, set its type, incorporate options, and call the solution routine SNESSolve :
Vec value_vector,solution_vector; /* vector creation code missing */ SNES solver; SNESCreate( comm,&solver ); SNESSetFunction( solver,value_vector,formfunction, NULL ); SNESSetFromOptions( solver ); SNESSolve( solver,NULL,solution_vector );
The function has the type
PetscErrorCode formfunction(SNES,Vec,Vec,void*)where the parameters are:
Example:
PetscErrorCode evaluation_function( SNES solver,Vec x,Vec fx, void *ctx ) { const PetscReal *x_array; PetscReal *fx_array; VecGetArrayRead(fx,&fx_array); VecGetArray(x,&x_array); for (int i=0; i<localsize; i++) fx_array[i] = pointfunction( x_array[i] ); VecRestoreArrayRead(fx,&fx_array); VecRestoreArray(x,&x_array); };
Comparing the above to the introductory description you see that the Hessian is not specified here. An analytic Hessian can be dispensed with if you instruct PETSc to approximate it by finite differences: \begin{equation} H(x)y \approx \frac{f(x+hy)-f(x)}{h} \end{equation} with $h$ some finite diference. The commandline option snes_fd forces the use of this finite difference approximation. However, it may lead to a large number of function evaluations. The option snes_fd_color applies a coloring to the variables, leading to a drastic reduction in the number of function evaluations.
If you can form the analytic Jacobian / Hessian, you can specify it with SNESSetJacobian , where the Jacobian is a function of type SNESJacobianFunction .
Specifying the Jacobian:
Mat J; ierr = MatCreate(comm,&J); CHKERRQ(ierr); ierr = MatSetType(J,MATSEQDENSE); CHKERRQ(ierr); ierr = MatSetSizes(J,n,n,N,N); CHKERRQ(ierr); ierr = MatSetUp(J); CHKERRQ(ierr); ierr = SNESSetJacobian(solver,J,J,&Jacobian,NULL); CHKERRQ(ierr);
crumb trail: > petsc-nonlinear > Time-stepping
For cases \begin{equation} u_t = G(t,u) \end{equation} call TSSetRHSFunction .
#include "petscts.h" PetscErrorCode TSSetRHSFunction (TS ts,Vec r, PetscErrorCode (*f)(TS,PetscReal,Vec,Vec,void*), void *ctx);
For implicit cases \begin{equation} F( t,u,u_t ) = 0 \end{equation} call TSSetIFunction
#include "petscts.h" PetscErrorCode TSSetIFunction (TS ts,Vec r,TSIFunction f,void *ctx)