jacobian_block Derived Type

type, public :: jacobian_block

A data type representing a submatrix of a Jacobian. Specifically, it represents the commonly occurring operation where is the differentiation operator in the -direction. Optionally, there can be an additional differentiation operator on the right-hand-side of this.

This data type is useful when constructing a preconditioner. A preconditioner, , should approximate the inverse Jacobian of a problem being solved. Rather than directly computing the inverse Jacobian, it is more efficient to approximate it. If is the vector being preconditioned, and is the result of applying the preconditioner, then Thus, the preconditioner can be applied by approximately solving this system for . Linearising , this system can be solved efficiently using Picard iteration.

Say that the Jacobian is an system of these blocks (each labeled as ) and that the vector being preconditioned constists of scalar fields (). Then the estimate of the solution for the field in the preconditioned vector () is the solution to Depending on the type of fields being used and the direction in which derivatives are being taken, may be tridiaganol, meaning it can be solved efficiently.

For this purpose, a type-bound multiplication operator is provided for the Jacobian block type, which can be used when evaluating the right hand side of the linear system. There is also a solve_for method, which takes as an argument the field representing the right hand side of the system.

Boundary conditions are a complicated issue. When constructing an instance of this type, locations in the raw field representation can be specified for which boundary conditions are given. By default these are all Dirichlet conditions, but this behaviour may be overridden to be Neumann conditions. Note that Neumann conditions result in approximately an order of magnitude lower accuracy. When using the Jacobian block for multiplation, the type of the boundary does not matter; the value at the boundary in the result will be set to 0 or to values produced by an optional user-provided function. When using the solve_for method, the tridiagonal matrix will be altered in the specified locations to reflect the correct boundary conditions. This effectively mimics the sorts of Jacobian rows typically produced by boundary conditions.


Inherits

type~~jacobian_block~~InheritsGraph type~jacobian_block jacobian_block type~jacobian_block->type~jacobian_block block_increment scalar_field scalar_field type~jacobian_block->scalar_field contents, derivative, field_increment

Inherited by

type~~jacobian_block~~InheritedByGraph type~jacobian_block jacobian_block type~jacobian_block->type~jacobian_block block_increment type~ice_shelf ice_shelf type~ice_shelf->type~jacobian_block thickness_jacobian, velocity_jacobian

Contents

Source Code


Components

TypeVisibility AttributesNameInitial
integer, private :: direction

The direction in which any derivatives are taken.

integer, private :: extra_derivative =no_extra_derivative

The direction in which to apply a differentiation on the right-hand-side of the Jacobian block operator. Defaults none.

class(scalar_field), private, allocatable:: contents

The value, , to which the Jacobian block operation is beiing applied.

real(kind=r8), private :: coef =1._r8

Optional coefficient by which the the term in the operator will be multiplied.

procedure(jacobian_block_bounds), private, pointer, nopass:: get_boundaries

A subroutine which determines the expected boundary conditions (and their location in the raw array) for the solution of the Jacobian block.

class(scalar_field), private, allocatable:: derivative

The cached derivative of contents

real(kind=r8), private, dimension(:), allocatable:: diagonal

The diagonal of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: super_diagonal

The super-diagonal of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: sub_diagonal

The sub-diagonal of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: l_multipliers

Multipliers defining the L matrix in the LU factorisation of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: u_diagonal

The diagonal of the U matrix in the LU factorisation of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: u_superdiagonal1

The first superdiagonal of the U matrix in the LU factorisation of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: u_superdiagonal2

The second superdiagonal of the U matrix in the LU factorisation of the tridiagonal matrix representation of this block.

integer, private, dimension(:), allocatable:: pivots

Pivot indicies from the LU factorisation of the tridiagonal matrix representation of this block.

real(kind=r8), private, dimension(:), allocatable:: boundary_vals

Expected boundary values for the solution to the Jacobian block.

integer, private, dimension(:), allocatable:: boundary_locs

Locations in the raw arrays which are used to specify boundary conditions.

integer, private, dimension(:), allocatable:: boundary_types

The types of boundary conditions, specified using the parameters found in boundary_types_mod.

real(kind=r8), private :: real_increment

A scalar value which is to be added to this Jacobian block (i.e. to the diagonal).

class(scalar_field), private, allocatable:: field_increment

A scalar field which is to be added to this Jacobian block (i.e. to the diagonal).

type(jacobian_block), private, pointer:: block_increment=> null()

Another Jacobian block which is to be added to this one

integer, private :: has_increment =0

Indicates whether or not there has been an increment added to this block. If not, then 0. If a scalar real value has been added, then 1. If a scalar value has been added, then 2.


Constructor

public interface jacobian_block

  • private function constructor(source_field, direction, extra_derivative, boundary_locs, boundary_types, boundary_operations, coef) result(this)

    Author
    Chris MacMackin
    Date
    December 2016

    Build a block in a Jacobian matrix, with the form where is a scalar field and is the differentiation operator in the -direction. Additionally, a further differentiation operator may be added to the right hand side of this matrix block. Optional arguments allow for handling of boundary conditions. See the end of the documentation of the jacobian_block type for a description of how boundary conditions are treated.

    Arguments

    Type IntentOptional AttributesName
    class(scalar_field), intent(in) :: source_field

    A scalar field () making up this block of the Jacobian

    integer, intent(in) :: direction

    The direction in which field derivatives are taken.

    integer, intent(in), optional :: extra_derivative

    If present, specifies the direction of a differentiation operator to be added to the right hand side of this matrix block.

    integer, intent(in), optional dimension(:):: boundary_locs

    The locations in the raw representation of rhs for which boundary conditions are specified. Defaults to there being none.

    integer, intent(in), optional dimension(:):: boundary_types

    Integers specifying the type of boundary condition. The type of boundary condition corresponding to a given integer is specified in boundary_types_mod. Only Dirichlet and Neumann conditions are supported. Defaults to Dirichlet. The order in which they are stored must match that of boundary_locs.

    procedure(jacobian_block_bounds), optional :: boundary_operations

    A function specifying the values to place at the boundaries of the result when using the Jacobian block for multiplication. By default, all boundaries are set to 0. The order in which the resulting values are stored should match that of boundary_locs.

    real(kind=r8), intent(in), optional :: coef

    An optional coefficient by which the the term in the operator will be multipled. Default value is 1.

    Return Value type(jacobian_block)

    A new Jacobian block


Type-Bound Procedures

procedure, private :: jacobian_block_multiply

  • private recursive function jacobian_block_multiply(this, rhs) result(product)

    Author
    Chris MacMackin
    Date
    December 2016

    Provides a matrix multiplication operator between a Jacobian block and a scalar field (which corresponds to a state vector).

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(scalar_field), intent(in) :: rhs

    A field corresponding to a state vector being multiplied by the Jacobian block.

    Return Value class(scalar_field), pointer

procedure, private :: jacobian_block_add_real

  • private function jacobian_block_add_real(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    December 2016

    Produces a Jacobian block which has been offset by some constant increment.

    Read more…

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    real(kind=r8), intent(in) :: rhs

    A scalar which should be added to this block

    Return Value type(jacobian_block)

procedure, private :: jacobian_block_add_field

  • private function jacobian_block_add_field(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    May 2017

    Produces a Jacobian block which has been offset by a scalar field.

    Read more…

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(scalar_field), intent(in) :: rhs

    A scalar which should be added to this block

    Return Value type(jacobian_block)

procedure, private :: jacobian_block_add_block

  • private function jacobian_block_add_block(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    May 2017

    Produces a Jacobian block which is the sum of two existing blocks. Boundary conditions are set by the first operand (this).

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(jacobian_block), intent(in), target:: rhs

    A second block which should be added to this block

    Return Value type(jacobian_block)

procedure, private :: jacobian_block_assign

  • private subroutine jacobian_block_assign(this, rhs)

    Author
    Chris MacMackin
    Date
    December 2016

    Copies the contents of the rhs Jacobian block into this one. It will safely deallocate any data necessary.

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(out) :: this
    type(jacobian_block), intent(in) :: rhs

procedure, private :: get_tridiag => jacobian_block_get_tridiag

  • private recursive subroutine jacobian_block_get_tridiag(this, diagonal, subdiagonal, superdiagonal)

    Author
    Chris MacMackin
    Date
    May 2017

    Computes the tridiagonal matrix used to solve for this Jacobian block.

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    real(kind=r8), intent(out), dimension(:), allocatable:: diagonal
    real(kind=r8), intent(out), dimension(:), allocatable:: subdiagonal
    real(kind=r8), intent(out), dimension(:), allocatable:: superdiagonal

generic, public :: operator(*) => jacobian_block_multiply

  • private recursive function jacobian_block_multiply(this, rhs) result(product)

    Author
    Chris MacMackin
    Date
    December 2016

    Provides a matrix multiplication operator between a Jacobian block and a scalar field (which corresponds to a state vector).

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(scalar_field), intent(in) :: rhs

    A field corresponding to a state vector being multiplied by the Jacobian block.

    Return Value class(scalar_field), pointer

  • private function jacobian_block_add_real(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    December 2016

    Produces a Jacobian block which has been offset by some constant increment.

    Read more…

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    real(kind=r8), intent(in) :: rhs

    A scalar which should be added to this block

    Return Value type(jacobian_block)

  • private function jacobian_block_add_field(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    May 2017

    Produces a Jacobian block which has been offset by a scalar field.

    Read more…

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(scalar_field), intent(in) :: rhs

    A scalar which should be added to this block

    Return Value type(jacobian_block)

  • private function jacobian_block_add_block(this, rhs) result(sum)

    Author
    Chris MacMackin
    Date
    May 2017

    Produces a Jacobian block which is the sum of two existing blocks. Boundary conditions are set by the first operand (this).

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(in) :: this
    class(jacobian_block), intent(in), target:: rhs

    A second block which should be added to this block

    Return Value type(jacobian_block)

generic, public :: assignment(=) => jacobian_block_assign

  • private subroutine jacobian_block_assign(this, rhs)

    Author
    Chris MacMackin
    Date
    December 2016

    Copies the contents of the rhs Jacobian block into this one. It will safely deallocate any data necessary.

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(out) :: this
    type(jacobian_block), intent(in) :: rhs

procedure, public :: solve_for => jacobian_block_solve

  • private function jacobian_block_solve(this, rhs) result(solution)

    Author
    Chris MacMackin
    Date
    December 2016

    Solves the linear(ised) system represented by this Jacobian block, for a given right hand side state vector (represented by a scalar field).

    Read more…

    Arguments

    Type IntentOptional AttributesName
    class(jacobian_block), intent(inout) :: this
    class(scalar_field), intent(in) :: rhs

    The right hand side of the linear(ised) system.

    Return Value class(scalar_field), pointer

Source Code

  type, public :: jacobian_block
    !* Author: Chris MacMackin
    !  Date: December 2016
    !
    ! A data type representing a submatrix of a
    ! Jacobian. Specifically, it represents the commonly occurring
    ! operation $$ \frac{\partial F}{\partial x_i} + F\Delta_i, $$
    ! where \( \Delta_i \) is the differentiation operator in the
    ! \(i\)-direction. Optionally, there can be an additional
    ! differentiation operator on the right-hand-side of this.
    !
    ! This data type is useful when constructing a preconditioner. A
    ! preconditioner, \(A\), should approximate the inverse Jacobian of
    ! a problem being solved. Rather than directly computing the
    ! inverse Jacobian, it is more efficient to approximate it. If
    ! \(d\) is the vector being preconditioned, and \(z\) is the
    ! result of applying the preconditioner, then $$ z = J^{-1}d
    ! \Rightarrow Jz = d.$$ Thus, the preconditioner can be applied
    ! by approximately solving this system for \(z\). Linearising
    ! \(J\), this system can be solved efficiently using Picard
    ! iteration.
    !
    ! Say that the Jacobian is an \(n\times n\) system of these blocks
    ! (each labeled as \(J_{j,k}\)) and that the vector being
    ! preconditioned constists of \(n\) scalar fields (\(d_j\)). Then
    ! the \(m^{th}\) estimate of the solution for the \(j^{th}\) field
    ! in the preconditioned vector (\(z^m_j\)) is the solution to $$
    ! J_{j,j}z^m_j = d_j - \sum_{\substack{k=1\ k\ne j}}^n
    ! J_{j,k}z^{m-1}_k. $$ Depending on the type of fields being used
    ! and the direction in which derivatives are being taken,
    ! \(J_{j,j}\) may be tridiaganol, meaning it can be solved
    ! efficiently. <!--Otherwise, it can be approximated that $$
    ! J_{j,j}z^m_j = \left(\frac{\partial F}{\partial x_i} +
    ! F\Delta_i\right)z^{m} \simeq \frac{\partial F}{\partial
    ! x_i}z^m_j + F\frac{\partial z^{m-1}_j}{\partial x_i}. $$ The
    ! first term in this approximation corresponds to a diagonal
    ! matrix (which can be solved trivially), while the second term is
    ! known and can be subtracted from the right-hand-side of the
    ! linear system.-->
    !
    ! For this purpose, a type-bound multiplication operator is
    ! provided for the Jacobian block type, which can be used when
    ! evaluating the right hand side of the linear system. There is
    ! also a `solve_for` method, which takes as an argument the field
    ! representing the right hand side of the system. <!--Before
    ! applying the latter operator, the `update_estimate` method must
    ! be called. This allows for the term involving derivative of the
    ! current estimate of the solution to be subtracted from the
    ! right-hand-side of the linear system, in cases where the system
    ! can not be expressed as a tridiagonal matrix.-->
    !
    ! Boundary conditions are a complicated issue. When constructing
    ! an instance of this type, locations in the raw field
    ! representation can be specified for which boundary conditions
    ! are given. By default these are all Dirichlet conditions, but
    ! this behaviour may be overridden to be Neumann conditions. Note
    ! that Neumann conditions result in approximately an order of
    ! magnitude lower accuracy. When using the Jacobian block for
    ! multiplation, the type of the boundary does not matter; the
    ! value at the boundary in the result will be set to 0 or to
    ! values produced by an optional user-provided function. When
    ! using the `solve_for` method, the tridiagonal matrix will be
    ! altered in the specified locations to reflect the correct
    ! boundary conditions. This effectively mimics the sorts of
    ! Jacobian rows typically produced by boundary conditions.
    !
    private
    integer                             :: direction
      !! The direction in which any derivatives are taken.
    integer                             :: extra_derivative = no_extra_derivative
      !! The direction in which to apply a differentiation on the
      !! right-hand-side of the Jacobian block operator. Defaults
      !! none.
    class(scalar_field), allocatable    :: contents
      !! The value, \(A\), to which the Jacobian block operation is
      !! beiing applied.
    real(r8)                            :: coef = 1._r8
      !! Optional coefficient by which the the \(\partial F/\partial x
      !! \) term in the operator will be multiplied.
    procedure(jacobian_block_bounds), pointer, nopass  :: &
                                           get_boundaries
      !! A subroutine which determines the expected boundary conditions
      !! (and their location in the raw array) for the solution of the
      !! Jacobian block.
    class(scalar_field), allocatable    :: derivative
      !! The cached derivative of `contents`
    real(r8), dimension(:), allocatable :: diagonal
      !! The diagonal of the tridiagonal matrix representation of this
      !! block.
    real(r8), dimension(:), allocatable :: super_diagonal
      !! The super-diagonal of the tridiagonal matrix representation
      !! of this block.
    real(r8), dimension(:), allocatable :: sub_diagonal
      !! The sub-diagonal of the tridiagonal matrix representation of
      !! this block.
    real(r8), dimension(:), allocatable :: l_multipliers
      !! Multipliers defining the L matrix in the LU factorisation of
      !! the tridiagonal matrix representation of this block.
    real(r8), dimension(:), allocatable :: u_diagonal
      !! The diagonal of the U matrix in the LU factorisation of
      !! the tridiagonal matrix representation of this block.
    real(r8), dimension(:), allocatable :: u_superdiagonal1
      !! The first superdiagonal of the U matrix in the LU
      !! factorisation of the tridiagonal matrix representation of
      !! this block.
    real(r8), dimension(:), allocatable :: u_superdiagonal2
      !! The second superdiagonal of the U matrix in the LU
      !! factorisation of the tridiagonal matrix representation of
      !! this block.
    integer, dimension(:), allocatable  :: pivots
      !! Pivot indicies from the LU factorisation of the tridiagonal
      !! matrix representation of this block.
    real(r8), dimension(:), allocatable :: boundary_vals
      !! Expected boundary values for the solution to the Jacobian
      !! block.
    integer, dimension(:), allocatable  :: boundary_locs
      !! Locations in the raw arrays which are used to specify
      !! boundary conditions.
    integer, dimension(:), allocatable  :: boundary_types
      !! The types of boundary conditions, specified using the
      !! parameters found in [[boundary_types_mod]].
    real(r8)                            :: real_increment
      !! A scalar value which is to be added to this Jacobian block
      !! (i.e. to the diagonal).
    class(scalar_field), allocatable    :: field_increment
      !! A scalar field which is to be added to this Jacobian block
      !! (i.e. to the diagonal).
    type(jacobian_block), pointer       :: block_increment => null()
      !! Another Jacobian block which is to be added to this one
    integer                             :: has_increment = 0
      !! Indicates whether or not there has been an increment added to
      !! this block. If not, then 0. If a scalar real value has been
      !! added, then 1. If a scalar value has been added, then 2.
  contains
    private
    procedure :: jacobian_block_multiply
    procedure :: jacobian_block_add_real
    procedure :: jacobian_block_add_field
    procedure :: jacobian_block_add_block
    procedure :: jacobian_block_assign
    procedure :: get_tridiag => jacobian_block_get_tridiag
    generic, public :: operator(*) => jacobian_block_multiply
    generic, public :: operator(+) => jacobian_block_add_real,  &
                                      jacobian_block_add_field, &
                                      jacobian_block_add_block
    generic, public :: assignment(=) => jacobian_block_assign
    procedure, public :: solve_for => jacobian_block_solve
  end type jacobian_block