ADF Developer Documentation 24/02/15

Writing the subroutine
Open up a file called CalcKinet icEnergy.d90 and copy and paste the following code to the file.

NOTE: It is worthwhile reading through the comments in this subroutine to give you an idea of
what is happening. The comments are preceded by "!". The very first comment gives a
description of the subroutine. Note that LaTeX comments can be added using the "[[" and "]]".
Following this very first comment, all other comments refer to the lines immediately following it.
(Except comments on the same line that a variable is declared, in which case the comment
refers to that variable.)
subroutine CalcKineticEnergy ( kineticEnergy )

! --------------------------------------------------------------------------
! Calculate the kinetic energy of the molecule.
!
! [[
! \mbox{kinetic energy} = \sum P_{\mu\nu}\int \varphi_\mu\nabla^2\varphi_\nu
! ]]
! --------------------------------------------------------------------------

! The following module contains the parameter,
! gModel%nspin = 0 (restricted), 1 (un-restricted).

use ModelDataModule

! The following module contains many indices, some of which are used
! in the other modules used in this subroutine.

use M_COMMON

! The following module contains the interface to
! the subroutine "calc_pmatbas_std" that we wish to use.

use pmat_interfaces

! Use the following modules M_grid, M_bas and M_eig
! for accessing data and subroutines concerned with:
! the integration grid, basis functions, and eigenvectors.

use M_grid
use M_eig
use M_bas

! Use the Vartypes module, which contains basic parameters,
! including 'KINT', 'KREAL'.
! Use "implicit none", for good programming practice.
! These two lines should be included in all ADF subroutines.

use Vartypes
implicit none

! The main result, the kinetic energy, will be stored in the
! variable "kineticEnergy", which has intent 'out'.

real(KREAL), intent (out) :: kineticEnergy

! Declare variables

type(grid) :: G ! integration grid
type(type_bas) :: BAS ! basis functions
type(type_eig) :: EIG ! eigenvectors

integer(KINT) :: iblock, i, mu, nu, ispin, k ! loop indices
real(KREAL), allocatable :: bas0(:,:), basL(:,:) ! basis function arrays
real(KREAL), allocatable :: pmat(:,:) ! P-matrix = 'density matrix'
real(KREAL), allocatable :: basMatrix(:) ! kinetic-energy matrix in basis representation
http://www.scm.com/Doc/Dev/doc.trunk/html/page57.html 1 / 12

each node only has to deal with certain blocks. ! So. bas0. which means: ! open TAPE10. ! and the Laplacian of the basis functions. total number of grid points = G%nblocks * G%npoints. bas0. i. call calc_bas_block (BAS.. integration blocks are distributed over the computer nodes.1) * BAS%num ) / 2. ! and the Laplacian of the basis functions. ! Each grid block contains G%npoints grid points. allocate ( basMatrix (BAS%num_tri) ) basMatrix = 0. ! for this block of grid points.html 2 / 12 . ! And. ! Here.scm. G%nblocks = number of integration grid 'blocks'. to calculate: ! basMatrix = < bas0 | Laplacian | bas0 > = < bas0 | basL > ! = INTEGRATE [ bas0 * basL * G%w ]. and set some parameters. iblock)) cycle iblock_ ! Get the integration coordinates and weights from file (i. ! Here. BAS%num_tri = ((BAS%num . ! This subroutine takes care of linear-scaling issues etc. basMatrix. ! ! Here. if (skip_block(G. call create (G) ! Allocate and set up basis function variable BAS. iblock_: do iblock = 1. basL. G) ! Allocate the arrays to be used for calculating ! the basis functions.0_KREAL ! Start the parallel timer call timers ('pp') ! Loop over the integration grid 'blocks'. basL. bas0. basL. ! so you don't have to worry about them. ! This also sets up all the linear-scaling parameters. call get_block(G) ! Calculate the value of the basis functions. ! basMatrix = INTEGRATE [ bas0 * basL * G%w ] = < bas0 | G%w | basL >. call create (BAS. BAS%num) ) ! Allocate and initialize the kinetic energy matrix. ! This is symmetric. call calc_basL_op_bas0_block (BAS. if the block of this loop is NOT on 'this' node then skip it. from TAPE10). ! So. ! G%npoints = number of points in a 'block' of grid points. ! on a block of grid points. G%w is acting like the 'operator'. bas0.e. G%nblocks ! When run in parallel. G. so a triangular matrix is used. BAS%num = number of basis functions. only a partial basMatrix is calculated on each node. allocate ( bas0 (G%npoints. allocate arrays. G.e. G%w. BAS%num) ) allocate ( basL (G%npoints. ! Therefore. ! in the M_bas module.FALSE.trunk/html/page57. basMatrix) http://www.com/Doc/Dev/doc. where G%w are the integration weights. basL) ! Use the 'overloaded' subroutine 'calc_basL_op_bas0_block'. ! ! Here. call alloc_init_commons (.ADF Developer Documentation 24/02/15 ! Initialise variables and allocate arrays in M_COMMONS.) ! 'Create' the integration grid. ! Use symmetry unique atoms = FALSE.

BAS%num do nu = 1.0. do ispin = 1. ! ! 'ispin' loops over the number of 'spins' = gModel%nspin.. ! so calculate the triangular index. ispin) * basMatrix(k) enddo enddo enddo ! Finish off with the factor of half. call timere ('pp') ! Deallocate the variables no longer needed. initialise the variable. 'basMatrix') ! End the parallel timer. allocate ( pmat(BAS%num_tri. call delete (EIG) ! Calculate the kinetic energy. the subroutine 'calc_pmatbas_std' uses the eigenvectors ! indexed according to an 'old' format. gModel%nspin = 2. orbital occupations. call ppcbnr (basMatrix. k if (mu > nu) then k = (mu*(mu-1))/2 + nu else k = (nu*(nu-1))/2 + mu endif kineticEnergy = kineticEnergy + pmat(k. BAS%num ! The matrix 'pmat' is triangular. EIG%froc are the orbital occupations. nu' loop over the number of basis functions. ! i. ! For restricted calculations. basL) call delete (G) ! Allocate and initialise eigenvectors.5 * Trace[ pmat * basMatrix ] ! = 0.. basMatrix = partial basMatrix from node 1 + partial basMatrix from node 2 + . ! Here. ! This is triangular matrix.0_KREAL ! In the following.com/Doc/Dev/doc.ADF Developer Documentation 24/02/15 enddo iblock_ ! Gather and add the results from all the computer nodes. kineticEnergy = . hence the use of EIG%eigbas_old. and close files. eigenvalues. ! Here.scm. ! Firstly.5 * SUM over basis functions: P-matrix * < bas0 | basL >. gModel%nspin do mu = 1. gModel%nspin) ) call calc_pmatbas_std (pmat. ! kineticEnergy = 0. pmat. size(basMatrix). EIG%froc) ! Dellocate the variable.html 3 / 12 .5_KREAL * kineticEnergy ! Deallocate arrays. EIG%eigbas_old. ! For UN-restricted calculations. deallocate (bas0.trunk/html/page57. call create (EIG) ! Allocate and calculate the electronic density matrix. kineticEnergy = 0. gModel%nspin = 1. ! ! 'mu. http://www.e.

ADF Developer Documentation 24/02/15 call delete (BAS) deallocate (basMatrix. call dealloc_init_commons end subroutine http://www. pmat) ! Deallocate arrays from M_COMMONS.html 4 / 12 .com/Doc/Dev/doc.scm.trunk/html/page57.

integral. http://www. integration blocks are distributed over the computer nodes. accessing grid information involved explicitly using the KF routines. moment(3) ! function.ADF Developer Documentation 24/02/15 Integrating a function over the integration grid Previously. 'Data') ! Initialise the integral and the moments to zero. call timers ('pp') ! Loop over the integration grid blocks. which contains integration grid weights and points. this piece of code will calculate: Here is the "old-style" using KF routines explicitly: ! DimensionsModule contains the global variable "gDims%lblock". moments real(KREAL) :: weight(gDims%lblock) ! integration grid weights real(KREAL) :: coord(gDims%lblock. in this case the function . 'Points') ! Open the section variable "Data".html 5 / 12 . "KREAL" ! Use implicit none. iblock_: do iblock = 1.0_KREAL ! Start the parallel timer. including "KINT". call kfopvr (iu. call kfopsc (iu.scm. ! These two lines should be included in all ADF subroutines. gDims%nblock ! When run in parallel. ! gDims%lblock = number of grid points in a block of grid points ! Total number of blocks = gDims%nblocks * gDims%lblock use DimensionsModule ! Use the Vartypes module. which contains basic parameters. call kfopfl (iu. 3) ! integration grid points (or coordinates) ! Open TAPE10 for reading.trunk/html/page67. Thus.com/Doc/Dev/doc. integer(KINT) :: iblock. integral.0_KREAL moment = 0. integral = 0. use Vartypes implicit none ! Declare variables. for good programming practice. iu ! loop indices real(KREAL) :: f. 'TAPE10') ! Open the file section "Points". i. The following piece of code illustrates the procedure for finding the integral and moment of a function f.

2)**2 + coord(i. call timere ('pp') ! Close TAPE10. but using the M_grid module. gDims%lblock f = exp ( . 1. but complications can arise when symmetry and parallelisation are used.html 6 / 12 .) to integrate functions. call kfclfl (iu) The above code is quite straight forward. call kfread (iu. moments ! "Create" the integration grid. allocate arrays.scm. '%'.ADF Developer Documentation 24/02/15 ! Therefore. the iu file-identifier could possibly be "hidden" to make the code clearer. moment(3) ! function. each node only deals with certain blocks. '%'.com/Doc/Dev/doc. ! If the block of this loop is NOT on "this" node then skip it. One can also use the integration grid modules in $ADFHOME/libt c/grid (i. if (skipbl(iblock)) cycle iblock_ ! Get the integration grid coordinates for this block. 'moment') ! End the parallel timer. i ! loop indices real(KREAL) :: f. integral. ! Use module M_grid ! for accessing data and subroutines concerned with ! the integration grid use M_grid use Vartypes implicit none ! Declare variables. 1:3)) ! Get the integration grid weights for this block. integral. which means: ! open TAPE10. Furthermore. 'integral') call ppcbnr (moment. and set some parameters call create (G) ! Initialise the integral and the moments to zero. 1:3) * f * w(i) end do end do iblock_ ! Gather and add the results from all the nodes. w (1:gDims%lblock)) ! Multiply function and its moment-integrand by integration weights ! and sum over this block of points do i = 1.e. etc. http://www.(coord(i. call kfread (iu. M_gridfunct ion.trunk/html/page67.1)**2 + coord(i. The following piece of code illustrates the previous example again.3)**2) ) integral = integral + f * w(i) moment(1:3) = moment(1:3) + coord(i. type(grid) :: G ! integration grid integer(KINT) :: iblock. M_grid. size(moment). call ppcbnr (integral. coord (1:gDims%lblock.

0_KREAL moment = 0. ! If the block of this loop is NOT on "this" node then skip it. if (skip_block(G. G%nblocks ! When run in parallel. and close files.TRUE.1)**2 + G%coord(i. iblock)) cycle iblock_ ! Get the integration coordinates and weights from file. call get_block(G) ! Multiply function and its moment-integrand by integration weights ! and sum over this block of points. 1.html 7 / 12 .2)**2 + G%coord(i. one can continue to use symmetry. call timers ('pp') ! Loop over the integration grid blocks. 1:3) * f * G%w(i) end do enddo iblock_ ! Gather and add the results from all the nodes. call create (G. Alternatively. integration blocks are distributed over the nodes.(G%coord(i. call timere ('pp') ! Deallocate arrays. logical. ! Therefore.scm.ADF Developer Documentation 24/02/15 integral = 0.0_KREAL ! Start the parallel timer. 'integral') call ppcbnr (moment. 'moment') ! End the parallel timer. One option is to run the job with no symmetry. call delete (G) If symmetry is used. iblock_: do iblock = 1. size(moment). USE_EQUIVALENT_BLOCKS) This ensures that the integration uses all grid points and not just those from the symmetry- unique wedge. only the symmetry-unique "wedge" of the grid is calculated.com/Doc/Dev/doc. parameter :: USE_EQUIVALENT_BLOCKS = . each node only deals with certain blocks. you want the whole grid. ! Here. http://www.trunk/html/page67.3)**2) ) integral = integral + f * G%w(i) moment(1:3) = moment(1:3) + G%coord(i. G%w = integration grid weights ! G%coord = integration grid points (or coordinates) do i = 1. Using symmetry can dramatically speed up a calculation. call ppcbnr (integral. G%npoints f = exp ( . however it may be that for the property you wish to calculate. but add the following to the previous piece of code.

html 8 / 12 . G) ! Allocate the arrays to be used for calculating the basis functions ! on a block of grid points. mu. matrix = 0.1) * BAS%num ) / 2 allocate ( matrix (BAS%num_tri) ) ! Initialise the matrix. ! Here.scm. ! Use the modules M_grid and M_bas ! for accessing data and subroutines concerned with: ! the integration grid and basis functions. type(grid) :: G ! integration grid type(type_bas) :: BAS ! basis functions integer(KINT) :: iblock. so that the matrix will be symmetric. i. ! Here.ADF Developer Documentation 24/02/15 Calculating a matrix element in the basis representation Very often one needs to find the matrix elements of an operator in the basis representation. So. use M_grid use M_bas use Vartypes implicit none ! Declare variables. allocatable :: op(:) ! operator ! Create the grid.com/Doc/Dev/doc. G%npoints = number of points in an integration grid block of points ! BAS%num = number of basis functions allocate ( bas0 (G%npoints. call timers ('pp') http://www.0_KREAL ! Start the parallel timer. "triangular". and basis functions we want the matrix elements: The following example assumes a scalar operator. allocatable :: matrix(:) ! matrix in basis representation. ! This also sets up all the linear-scaling parameters.BAS%num) ) ! Allocate the matrix. allocatable :: bas0(:. triangular real(KREAL). call create (G) ! Allocate and set up basis function variable BAS. for an operator .trunk/html/page68. or in other words. This is triangular. nu ! loop indices real(KREAL). which opens TAPE10 and allocates arrays.:) ! basis functions real(KREAL). call create (BAS. BAS%num_tri = ((BAS%num .

! Therefore. bas0. call get_block(G) ! Calculate the values of the basis functions. ! This routine takes care of linear-scaling issues etc. op = op * G%w ! Now multiply the operator "op" by the basis functions. ! This uses an "overloaded" subroutine from the M_bas module.scm. op.html 9 / 12 . iblock)) cycle iblock_ ! Get the integration coordinates and weights from file. deallocate (bas0. each node only deals with certain blocks. G%nblocks ! When run in parallel. and close files. matrix) call delete (BAS) call delete (G) http://www. here. 'matrix') ! End the parallel timer. ! on this block of grid points. bas0) ! Define a "scalar" operator. op. G%w. ! This uses an "overloaded" subroutine from the M_bas module. iblock_: do iblock = 1. size(matrix). ! If the block of this loop is NOT on "this" node then skip it. call calc_bas_block (BAS. matrix) enddo iblock_ ! Gather and add the results from all the nodes. G. call ppcbnr (matrix.ADF Developer Documentation 24/02/15 ! Loop over the integration grid blocks.com/Doc/Dev/doc. bas0. op = "Some definition" ! Multiply the operator by the integration weights. call timere ('pp') ! Deallocate arrays.trunk/html/page68. G. integration blocks are distributed over the nodes. if (skip_block(G. call calc_bas0_op_bas0_block (BAS.

for efficiency. to indicate the order of the derivative 0. so that Y gets the "inner"-loop index. i. For example. For the kinetic energy matrix we use the subroutine calc_bas0_op_basL_block. allocatable :: gradMatrix(:. that we have to change sign on certain components. 2 and "L" for laplacian. NOTE: that X and Y get "swapped" in the above formula.trunk/html/page69. However. it uses the subroutine calc_bas0_op_bas1_block.:.html 10 / 12 . 1.:. This subroutine will take and return either a triangular matrix or a square matrix. However.com/Doc/Dev/doc. where the operator contains derivatives. we consider the kinetic operator. The kinetic energy matrix is symmetric. allocatable :: kinMatrix(:) ! kinetic matrix in basis representation real(KREAL). use M_grid use M_bas use Vartypes implicit none ! Declare variables. and the "gradient" operator . 1. Note that the naming convention of these routines is of the form: Here X and Y take values 0.:) ! basis function derivatives real(KREAL). allocatable :: bas0(:. L. type(grid) :: G ! integration grid type(type_bas) :: BAS ! basis functions integer(KINT) :: iblock.dmod5.:)! gradient matrix in basis representation real(KREAL). mu. op is the operator. 2. we'll use a square matrix. for simplicity. allocatable :: op(:) ! operator http://www. and therefore.ADF Developer Documentation 24/02/15 Calculating matrix elements with a derivative operator Very often one needs to find the matrix elements of an operator in the basis representation. allocatable :: bas1(:. allocatable :: basL(:.:) ! basis functions real(KREAL). and to illustrate the "overloaded" nature of the subroutine calc_bas0_op_bas1_block. nu ! loop indices real(KREAL). The "gradient" matrix is anti-symmetric. Thus we wish to calculate the following matrices and This code makes use of "overloaded" subroutines in the module $ADFHOME/adf/new_gradient s/M_bas. This can be important when considering signs.scm. a triangular matrix will be used. as long as it is remembered that when multiplying by another matrix. ! Use the modules M_grid and M_bas ! for accessing data and subroutines concerned with: ! the integration grid and basis functions. we can also get away with using a triangular matrix here. In this example.:) ! basis function Laplacian real(KREAL).

! This routine takes care of linear-scaling issues etc. bas0. if (skip_block(G. bas0. bas0. iblock)) cycle iblock_ ! Get the integration coordinates and weights from file. basL. G%w. G%npoints = number of points in an integration grid block of points ! BAS%num = number of basis functions allocate ( bas0 (G%npoints. iblock_: do iblock = 1.ADF Developer Documentation 24/02/15 ! Create the grid. bas0. which opens TAPE10 and allocates arrays. gradMatrix = 0. each node only deals with certain blocks. ! In this case. ! Here. G. integration blocks are distributed over the nodes. BAS%num) ) allocate ( basL (G%npoints. op = G%w ! Now multiply the operator "op" by the basis functions. ! First the "gradient" matrix. basL. ! This uses an "overloaded" subroutine from the M_bas module. gradMatrix) ! Second the kinetic energy matrix call calc_bas0_op_basL_block (BAS.trunk/html/page69. bas1. ! on a block of grid points. op. op. http://www. G. call timers ('pp') ! Loop over the integration grid blocks. BAS%num. and Laplacians. ! This also sets up all the linear-scaling parameters.0_KREAL ! Start the parallel timer. ! basis function derivatives. kinMatrix) enddo iblock_ ! Gather and add the results from all the nodes. op. bas1.html 11 / 12 . G%nblocks ! When run in parallel. BAS%num = number of basis functions ! BAS%num_tri = number in triangular array ! = ((BAS%num . call get_block(G) ! Calculate the values of the basis functions. ! Therefore. ! on this block of grid points. G) ! Allocate the arrays to be used for calculating the basis functions. call create (G) ! Allocate and set up basis function variable BAS. G. call create (BAS. call calc_bas0_op_bas1_block (BAS. bas0. ! If the block of this loop is NOT on "this" node then skip it.1 ) * BAS%num ) / 2 allocate ( gradMatrix (3. BAS%num) ) allocate ( bas1 (G%npoints. ! This uses an "overloaded" subroutine from the M_bas module. here. call calc_bas_block (BAS.scm. 3. the operator is just the integration weights.0_KREAL kinMatrix = 0. basL) ! Define a "scalar" operator. BAS%num) ) allocate ( kinMatrix (BAS%num_tri) ) ! Initialise the matrices. bas1.com/Doc/Dev/doc. BAS%num) ) ! Allocate the matrices ! Here.

kinMatrix) call delete (BAS) call delete (G) http://www.trunk/html/page69. gradMatrix.com/Doc/Dev/doc.html 12 / 12 . and close files. call timere ('pp') ! Deallocate arrays. 'gradMatrix') call ppcbnr (kinMatrix.scm. size(gradMatrix). basL. deallocate (bas0. 'kinMatrix') ! End the parallel timer. bas1. size(kinMatrix).ADF Developer Documentation 24/02/15 call ppcbnr (gradMatrix.