Jacobian Calculation

Jacobian calculation

Special mention of calcJacobianComplex.

One of the most involved parts of Newton's method is forming the Jacobian. The NonlinearSolvers module contains the function physicsJac to compute the Jacobian of the physics $\frac{\partial R(q)}{\partial q}$, where $R$ is evalResidual. This function can be used by other methods as a starting point for computing the residual of $g(R(q))$ described in Newton's method page.

This function computes the Jacobian of an evalResidual-like function. Specifically, it computes \partial (eqn.q_vec)/ \partial (eqn.res_vec).

Other users of newtonInner (for example, implicit time marching methods) will need to implemnt their own version of this function. The documentation for this function describes the requirements for the other implementations.

`newtonInner guarantees that eqn.q and eqn.q_vec will be consistent when this function is called. When using finite differences, eqn.res and eqn.res_vec must contain the residual of the physics.

Inputs:

  • mesh: an AbstractMesh

  • sbp: an SBP operator

  • eqn: an AbstractSolutionData, eqn.res and eqn.res_vec may be overwritten

  • opts: options dictonary

  • jac: the Jacobian, can be an Array, SparseMatrixCSC, or PetscMat

  • ctx_residual: a tuple of values. ctx_residual[1] must be an evalResidual-like function (eqn.q -> eqn.res) function with signature func(mesh, sbp, eqn, opts, t). See physicsRhs for a more thorough description of ctx_residual.

  • t: simulation time

Options Keys:

  • jac_type

  • jac_method

  • epsilon

  • calc_jac_explicit

Implementation Notes:

This function should not have to do any parallel communication. newtonInner ensures that the rhs_func is called before jac_func, and rhs_func handles the parallel communication.

Implementations of this function may perform either (eqn.q -> jacobian) or (eqn.q_vec -> jacobian). The first may be more computationally efficient, but the second can be simpler for debugging.

This function supportes several types of jacobians (dense arrays, SparseMatrixCSC, PetscMat), and several methods for calculating them (finite difference and complex step). Any function calling this function should support them as well.

It is strongly recommneded to use this function to compute the spatial jacobian and them modify the resulting matrix (this function zeros the Jacobian matrix)

When using Petsc matrices, the function may do intermediate assemblies (PETSC_FLUSH_ASSEMBLY), but does not need to do the final assembly.

source

physicsJac calls one of several functions to compute the Jacobian. Users should not call these functions directly, they should use physicsJac. There are two approaches to computing the Jacobian: using finite differences/complex step and calculating the entries of the matrix explicitly. The latter approach is much faster than the former, however the former does not require the physics module differentiate evalResidual.

Finite Differencing/Complex Step

The functions calcJacFD and calcJacobianComplex compute the Jacobian as a dense matrix, one column at a time. This is very slow and only useful for debugging small cases. A more efficient method is implemented in calcJacobianSparse, which uses a graph coloring approach to perturb the solution at several nodes simultaneously.

NonlinearSolvers.calcJacFD

This function calculates the Jacobian using finite differences, perturbing one degree of freedom at a time. This is slow and not very accurate. The Jacobian is calculated about the point in eqn.q_vec.

Inputs: mesh: AbstractMesh sbp: SBP operator eqn: AbstractEquation object opts: options dictionary pert: perturbation to use the finite differences. Must be of type Tsol. func: residual evaluation function res_0: vector containing residual at the point the Jacobian is calculated

Inputs/Outputs: jac:: Jacobian matrix to be populated. Must be a dense matrix

Aliasing restrictions: res_0 must not alias eqn.res_vec

At the start, calcJacFD assumes: The Jacobian will be calculated at the state that is specified in eqn.q_vec . res_0 should have the residual at that state in it

At exit, eqn.q_vec will have the same values as at the start.

eqn.q and eqn.res will be overwritten in the course of this function.

source

NonlinearSolvers.calcJacComplex

This function calculates the Jacobian (dense) using the complex step method, perturbing one degree of freedom at a time. This is very slow. The jacobian is calculated about the point in eqn.q_vec.

Inputs: mesh: AbstractMesh sbp: SBP operator eqn: AbstractEquation object opts: options dictionary pert: perturbation to use. Must be of type Tsol. func: residual evaluation function

Inputs/Outputs: jac:: Jacobian matrix to be populated. Must be a dense matrix

Aliasing restrictions: res_0 must not alias eqn.res_vec

source

NonlinearSolvers.calcJacobianSparse

This function calculate the Jacobian sparsely (only the entries within the sparsity bounds), using either finite differences or algorithmic differentiation. The jacobian is calculated about the point stored in eqn.q (not eqn.q_vec). A mesh coloring approach is used to compute the jacobian. Both eqn.q and the MPI send and receive buffers are perturbed during this process.

Inputs: mesh: AbstractMesh sbp: SBP operator eqn: AbstractEquation object opts: options dictionary pert: perturbation to use for the algorithmic differentiation. Currently, only complex numbers are supported. func: residual evaluation function (eqn.q -> eqn.res) res_0: element-based (3 dimensional) array containing the residual evaluated at the point where the Jacobian is being calculated. This is only used for finite differences (can be a 0 x 0 x 0 array otherwise).

Inputs/Outputs: jac: Jacobian matrix. Must be a sparse matrix type of some kind, (including PetscMat).

Aliasing restrictions: res_0 must not alias eqn.res

source

NonlinearSolvers.applyPerturbation

This function applies a perturbation to a the specified degree of freedom on each element according to a mask.

Because this is element based perturbation, opts["parallel_data"] must be "element".

Inputs: mesh: an AbstractMesh color: the color to perturb pert: perturbation to apply. Can be any datatype i: local degree of freedom number (in range 1:numDofPerNode) to perturb j: local node number (in range 1:numNodesPerElement) to perturb

Inputs/Outputs: arr: element based (3D) array of values to perturb shared_data: array of SharedFaceData for ghost elements to be perturbed The receive buffers are perturbed according to the masks in mesh.shared_element_colormasks, the send buffers are perturbed consistently with arr.

Aliasing restrictions: none

source

Assembles the volume integral contribution.

source

This function assembles the jacobian contribution for a single element into the matrix, when the jacobian is computed using finite differences. This is used by coloring-based methods for computing the jacobian.

Inputs:

  • helper: a AssembleData object

  • mesh: AbstractMesh object

  • eqn: AbstractEquation

  • res_arr: element-based (3D) array of perturbed residual values

  • res_0: element-based (3D) array of non-perturbed residual values

  • el_res: element number of the element we are observing the change in

  • el_pert: element number of the element that was perturbed

  • dof_pert: the degree of freedom number of the perturbed dof

  • epsilon: magnitude of perturbation

Inputs/Outputs:

  • jac: any kind of matrix (dense, SparseMatrixCSC, PetscMat)

Aliasing restrictions: res_arr and res_0 must not alias each other.

source

Same as other method, but for complex numbers. See that method for details. res_0 is not used in this case

source

Inputs

  • helper: an _AssembleElementData

  • mesh: a mesh

  • elnum: element number

  • jac: 4 dimensional array containing the jacobian of the element

jac contains the data for the jacobian of the volume terms for a given element. $jac[i, j, p, q] = \partial R[i, p, elnum] / \partial eqn.q[j, q, elnum]$. Its size is numDofPerNode x numDofPerNode x numNodesPerElement x numNodesPerElement.

source

NonlinearSolvers.calcJacCol

This function extracts the entries for one column of the Jacobian from two residual evaluates that come from finite differences.

Inputs: res_0: vector of unperturbed residual values res: vector of perturbed residual values epsilon: magnitude of perturbation

Inputs/Outputs: jac_row = vector to be populated with the Jacobian entries

Aliasing restrictions: res_0 and res cannot alias (obviously).

source

NonlinearSolvers.calcJacCol

This function extracts the entries for one column of the Jacobian from a complex step residual evaluation

Inputs: res: vector of perturbed residual values epsilon: magnitude of perturbation

Inputs/Outputs: jac_row = vector to be populated with the Jacobian entries

Aliasing restrictions: none

source

Explicit Calculation

The most efficient method to compute the Jacobian is to explicitly compute all its entries and assemble them into a matrix. The evalJacobian function must be extended by each physics module for this to work. This function is passed all the same arguments as evalResidual plus an additional _AssembleElementData object which is used to assemble the contribution of each element or interface into the matrix.

Helper object for assembling element and interface jacobians into the system matrix.

Fields

  • A: the matrix (can be Array, SparseMatrixCSC, or PetscMat)

  • idx: temporary array for row indices, length numDofPerNode

  • idy: temporary array for column indices, length numDofPerNode

  • vals: temporary array for matrix entries, size numDofPerNode square

  • idx_i: temporary array for row indices when assembling interface jacobians, length 2 x numDofPerNode

  • idy_i: like idx_i, but for column indices

  • vals_i: temporary array for storing matrix entries when assembling interface jacobians, size 2 x numDofPerNode square

source

Outer constructor for _AssembleElementData

source

An empty _AssembleElementData. Useful for giving a default value to fields.

source

Inputs

  • helper: an _AssembleElementData

  • mesh: a mesh

  • elnum: element number

  • jac: 4 dimensional array containing the jacobian of the element

jac contains the data for the jacobian of the volume terms for a given element. $jac[i, j, p, q] = \partial R[i, p, elnum] / \partial eqn.q[j, q, elnum]$. Its size is numDofPerNode x numDofPerNode x numNodesPerElement x numNodesPerElement.

source

Assembles contributions into an element-block matrix. jacLR and jacRL are not used.

source

Assembles the jacobian of an interface into the matrix. Specialized versions take advantage of the sparsity of the sbpface.

Inputs

  • helper: _AssembleElementData

  • sbpface: an SBP face object

  • mesh: a mesh

  • iface: an Interface object identify the interface to be assembled

  • jacLL: see below

  • jacLR:

  • jacRL

  • jacRR

jacAB where A = L or R and B = L or R, is the jacobian of the residual of element A with respect to the solution of element B.

jacAB has the same size/layout as jac in assembleElement.

source

Assembles contribution of the shared face terms into the element-block matrix. jacLR is not used.

source

Assemble one half of an interface, used by shared face integrals. See assembleInterface.

Inputs

  • helper: _AssembleElementData

  • sbpface: an SBP face object

  • mesh: a mesh

  • jacLL

  • jacLR

source

Assembles the boundary terms into an element-block matrix.

source

Assembles the jacobian of a boundary integral into the matrix. Specialized versions take advantage of the sparsity of the sbpface.

Inputs

  • helper: _AssembleElementData

  • sbpface: an SBP face object

  • mesh: a mesh

  • jac: a jac, same layout as assembleElement

source