Developers

The EPW team welcome any new development to the code.


How to become an EPW developer


Please follow the following steps:

  • Register on GitLab at https://gitlab.com/
  • Fork the QE project at https://gitlab.com/QEF/q-e
  • Do you developments following EPW coding style (see below)
  • Run the test-farm. Go to q-e/test-suite and run make run-tests-epw-parallel
  • (optional but recommanded) Compile the code in sequential without MPI and run the test-farm in sequential with make run-tests-epw-serial
  • Make a pull request

It is also good to contact one of us via email.


EPW good coding practice


Here are some good coding practice that we would like to implement in EPW (some might not be fully respected in the code yet):

  • Compile your code with -O0 -Wall flags. Make sure that you do not introduce unused variables etc...
  • FFLAGS = -O2 -g -Wall -fbounds-check -frange-check -finit-integer=987654321 -finit-real=nan -finit-logical=true -finit-character=64
  • Make your code ready for automatic documentation (Ford). Document the subroutine purpose and variables (also local variables) using !! below the variable name.
  • Do use INTENT (in/out) when you pass variables to a subroutine.
  • Make sure that your developments will not break the test-farm. You can run the tests in QE/test-suites.
  • Always use the ONLY keyword when you call a module with USE.
  • Do NOT use #ifdef __PARA except if truly required (e.g. if you directly call an MPI routine and you do not use the QE wrapper).
  • Do NOT use IF( ALLOCATED(var1) ) DEALLOCATE(var1). The variable should be correctly allocated and deallocated and should not be called more than necessary.

EPW coding style

  • Preprocessing options should be capitalized and start with two underscores. Examples: __MPI, __LINUX, ... Use preprocessing syntax #if defined (XXX), not #if defined XXX or #ifdef XXX
  • Fortran commands should be capitalized: CALL something( )
  • Variable names should be lowercase: foo = bar/2
  • use "DP" (defined in module kinds) to define the type of real and complex variables
  • conversions should be explicitly indicated. For conversions to real, use DBLE, or else REAL(...,KIND = DP). For conversions to complex, use CMPLX(...,...,KIND = DP). For complex conjugate, use CONJG. For imaginary part, use AIMAG. IMPORTANT: Do not use REAL or CMPLX without KIND = DP, or else you will lose precision (except when you take the real part of a double precision complex number).
  • Do not use automatic arrays (e.g. REAL(KIND = DP) :: A(N) with N defined at run time) unless you are sure that the array is small in all cases: large arrays may easily exceed the stack size, or the memory size
  • Do not use pointers unless you have a good reason to: pointers may hinder optimization. Allocatable arrays should be used instead.
  • If you use pointers, nullify them before performing tests on their status.
  • Be careful with F90 array syntax and in particular with array sections. Passing an array section to a routine may look elegant but it may turn out to be inefficient: a copy will be silently done if the section is not contiguous in memory (or if the compiler decides it is the right thing to do), increasing the memory footprint.
  • Do not pass unallocated arrays as arguments, even in those cases where they are not actually used inside the subroutine: some compilers don't like it.
  • Always use IMPLICIT NONE and declare all local variables. All variables passed as arguments to a routine should be declared as INTENT(in), (out), or (inout). All variables from modules should be explicitly specified via USE module, ONLY : variable. Variables used in an array declaration must be declared first, as in the following example:
    INTEGER, INTENT(in) :: N
    REAL(KIND = DP), INTENT(out) :: A(N)

in this order (some compilers complain if you put the second line before the first).

Typical header of subroutines

!------------------------------------------------------------------------
SUBROUTINE name(arg1, arg2)
!------------------------------------------------------------------------
!!
!!  Description of subroutine
!!
!------------------------------------------------------------------------
USE kinds,         ONLY : DP
USE cell_base,     ONLY : at, bg, alat
!
IMPLICIT NONE
!
!  input variables
!
INTEGER, INTENT(in) :: arg1
!! Description
REAL(KIND = DP), INTENT(in) :: arg2(3, 5)
!! Description
!
! Local variables
!
INTEGER :: ik
!! Description


!------------------------------------------------------------------------
END SUBROUTINE name 
!------------------------------------------------------------------------

Indentation

Use two spaces for indentation

DO ik = 1, nkf
  DO imode = 1, nmodes
    code
  ENDDO
ENDDO 

Spaces

Leave one space after a comma "," and between "multiple conditions" in a IF statement

IF (cond) THEN
  CALL name(arg1, arg2, arg3)
ENDIF
ALLOCATE(var1(dim1, dim2), STAT = ierr)
IF (ierr /= 0) CALL io_error('Error allocating var1 in subroutine_name')

DO ik = 1, nkf
  ikk = 2 * ik - 1
  ikq = 2 * ik
  IF ((MINVAL(ABS(var1(:, ikk) - ef)) < fsthick) .AND. (MINVAL(ABS(var1(:, ikq) - ef)) < fsthick)) THEN
ENDDO

DEALLOCATE(var1, STAT = ierr)
IF (ierr /= 0) CALL io_error('Error deallocating var1 in subroutine_name')

Allocating and deallocating arrays

Check the status once an array is allocated or deallocated

ALLOCATE(var1(dim1, dim2), STAT = ierr)
IF (ierr /= 0) CALL errore('subroutine_name', 'Error allocating var1', 1)

DEALLOCATE(var1, STAT = ierr)
IF (ierr /= 0) CALL errore('subroutine_name', 'Error deallocating var1', 1)

Reading and writing files

Leave one space after a comma "," and after a statement

OPEN(UNIT = file_unit, FILE = 'file_name', STATUS = 'old', FORMAT = 'formatted', IOSTAT = ios)
IF (ios /= 0) CALL errore('subroutine', 'error opening file_name', iunit_name)
READ(file_unit) index
CLOSE(file_unit)

OPEN(UNIT = file_unit, FILE = 'file_name', STATUS = 'old', FORMAT = 'formatted', IOSTAT = ios)
IF (ios /= 0) CALL errore('subroutine', 'error opening file_name', iunit_name)
WRITE(file_unit, '(i7)') index
CLOSE(file_unit)

Intrinsic functions

Use capital letters when calling an intrinsic function or logicals:

a = MATMUL(c, d)
c = TRANSPOSE(DBLE(e))
f = .TRUE.

Relational operator

Use modern relational operators:

> instead of .gt.
< instead of .lt.
== instead of .eq.
/= instead of .neq.

Mathematical operator

Use one space between mathematical operators

a = b + i
c = c / SQRT(s)

Spaces in the code

Avoid white space in the code. When a space is need, add a comment (!) that follows the indentation:

!
a = b
! 
DO i = 1, n
  !
  y = a + c
ENDDO

Conditional allocation

Do NOT use:

IF (.NOT. ALLOCATED(var)) ALLOCATE(var(dim1))

but rather use

ALLOCATE(var1(dim1, dim2), STAT = ierr)
IF (ierr /= 0) CALL errore('subroutine_name', 'Error allocating var1', 1)

Indeed conditional allocations create memory leaks and can always be avoided.

Order of declaration

The recommanded order is as follow:

CHARACTER(LEN = 256) :: var
LOGICAL :: var
LOGICAL, ALLOCATED :: var(:)
INTEGER :: var
INTEGER, ALLOCATED :: var(:) 
REAL(KIND = DP) :: var
REAL(KIND = DP), ALLOCATED :: var(:)
COMPLEX(KIND = DP) :: var
COMPLEX(KIND = DP), ALLOCATED :: var(:)

First all INTENT variables are declared (in that order) and then all the local variables are declared (in that order).

Note: Do not use "DIMENSION(:)"

Use of capital letters

Do not use capital letters in variables (even if only first letter). Capital letters are reserved for function, subroutines, kinds, intrinsic etc..