Hello!
If you create a CVodesIntegrator instance, or a function which contains calls to a CVodesIntegrator instance, you can calculate both forward and adjoint sensitivities by using the "setFwdSeed/setAdjSeed" functions (see user guide for details). I guess you refer to the question of how Jacobians and Hessians are calculated.
In CasADi, Hessians are calculated by using the adjoint mode to calculate the gradient of the Lagrangian. Here, this will result in a backwards integration problem being formulated internally in a new CVodes instance. The Hessian is then calculated by applying the forward mode algorithmic differentiation to the gradient of the Lagrangian, which will internally result in forward sensitivity analysis applied to the forward and backward problems (so-called forward-over-adjoint sensitivity analysis). This essentially gives a way to calculate Hessian-times-vector product. The complete Hessian is then assembled using a graph coloring algorithm (starcoloring).
For Jacobians, the situation is a bit different. Here the heuristic is that first the sparsity pattern of the Jacobian is calculated and then graph coloring techniques are applied to determine the smallest number of forward or adjoint derivatives needed to calculate the Jacobian. If the forward mode requires less than twice the number of directions compared to the adjoint mode, the forward mode is selected, otherwise the adjoint mode. You can override this my setting the option "ad_mode" to "forward" or "reverse" for the constraint function (before the Jacobian of the constraint function is formed).
The same approach is used both for the Jacobian of the (NLP) constraints and for the Jacobian of the ODE right-hand-side. The latter is passed to CVodes to use during the integration (CVodes is using an implicit method).
In the vdp_single_shooting.py example, the Jacobian of the constraints is dense and has two rows and 20 columns and therefore the adjoint mode is selected (2 directions is less then half of 20). I want to stress that vdp_single_shooting.py is mainly a demonstration on how integrators can be embedded into optimization problems in CasADi. For solving practical optimal control problem, we recommend looking at the other examples, in particular the ones involving collocation.
I hope this makes things more clear!
Joel