Coding Conventions

Banned functions and syntax

  • line numbers
    they are a relict of the deprecated goto statement and not needed
  • call flush
    use flush(6) instead of call flush(6)
    the subroutine is a vendor extension and Intel Fortran might crash when using call flush() (i.e. without file unit specified), while using flush() is recognized as a syntax error
  • print*,
    use write(6,*) instead of print*,
  • stop
    use the quit() subroutine provided by DAMASK
  • return
    is not needed immediately before end of subroutine/function
  • .lt., .le., .eq., .ne., .gt., and .ge.
    use the more readable comparison symbols <, <=, ==, !=, >, and >=
  • (/ and /)
    use the more readable [ and ]

Data declaration

General

  • always state implicit none before data declaration
  • use the following order when assigning attributes:
    1. type / kind
    2. dimension
    3. allocatable / pointer / target / parameter
    4. private / public (protected) intent(in/out/inout)
    5. optional

Modules

  • always state private after implicit none
  • order of data declaration
    1. constants/variables
      1. public
        1. parameter
        2. protected
      2. private
    2. functions/subroutines
      1. public
      2. private

Functions

  • functions have no intent(out) or intent(inout) dummy variables
  • when possible, add the pure statement directly before the declaration
  • return value specification:
    • scalar: use real(pReal) or integer(pInt) before the function declaration
    • array: use the first possible variable (after implicit none and possibly information needed for dimension)
  • order of data declaration
    1. intent(in)
    2. parameter
    3. local variables

Subroutines

  • when possible, add the pure statement directly before the declaration
  • order of data declaration
    1. intent(out)
    2. intent(inout)
    3. intent(in)
    4. parameter
    5. local variables

Naming Scheme

  • global, read-only variables (public, protected) are prefixed by the name of the module
  • parameters are written in CAPITALS
  • global, read-write variables are prefixed only if necessary
  • suffix with shape, but without underscore: C66 instead of C_66

loops:

  • i for integration point number
  • e for element number
  • g for grain number
  • h for homogenization instance
  • m for material instance
  • c for constituent instance
  • o for output
  • f for slip/twin family

distinct:

  • ip for integration point number
  • ipc component-ID of current integration point
  • el for element number
  • gr for grain number
  • is ipc and gr the same?
  • state
  • Tstar_v

Indentation and line format

  • no indentation for modules/programs and functions/subroutines
  • 2 spaces per level
  • line ends after 100 characters, hard limit by compiler is 132
  • OMP directions have no effect on indentation

Comments

  • use doxygen tags to describe functions, variables, and parameters
  • structure longer functions

Recommendations

  • use named control structures (do, if, where, forall, select case)

    ✅                                             ❌
    subIncLooping: do i=1_pInt, 1000_pInt           do i=1_pInt, 1000_pInt
      a=time(i)                                       a=time(i)
    enddo  a=time(i)                                enddo


  • use spread when initializing fields instead of explicit loops

    real(pReal), dimension(3,3,10) :: a
    ✅                                             ❌
    a=spread(math_I3,3,10)                          a=0.0_pReal
                                                    do i=1_pInt, 10_pInt
                                                      a(1:3,1:3,i)=math_I3
                                                    enddo


  • use sum when calculating average fields instead of explicit loops

    real(pReal), dimension(3,3,10) :: a
    real(pReal), dimension(3,3) :: b
    ✅                                             ❌
    b=sum(a,3)                                      b=0.0_pReal
                                                    do i=1_pInt, 10_pInt
                                                      b=b + a(1:3,1:3,i)
                                                    enddo


  • use product when calculating products of array

    integer(pInt), dimension(3) :: res
    integer(pInt), :: N
    ✅                                             ❌
    N=product(res)                                  N=res(1)*res(2)*res(3)


  • use no assumed size/shape, use explicit ranges
    integer(pInt), dimension(3,3,5,5) :: field
    integer(pInt), dimension(3,3) :: tensor
    ✅                                             ❌
    field(1:3,1:3,1,1)=tensor                       field(:,:,1,1)=tensor

  • avoid public data, try to use accessor functions

Use statements

  • use the only statement and explicitly include functions of the module

    integer(pInt) function a(b)
    ✅                                             ❌
    use IO, only: &                                 use IO
      IO_error, &
      IO_warning

Resources