Coding Conventions#

Fortran#

Discouraged Functions and Syntax#

line numbers

They are a relict of the deprecated goto statement and not needed.

write(*,*)

A print* statement is easier to read than write(*,*).

return

This statement is superfluous at the end of a subroutine/function.

.lt., .le., .eq., .ne., .gt., and .ge.

The more readable comparison symbols <, <=, ==, !=, >, and >= are preferred.

(/ and /)

The more readable [ and ] are preferred.

Data Declaration#

Modules#

  • Public variables are discouraged in favor of object-oriented get and set functionality.

  • Unless the whole module is public, implicit none needs to be followed by private.

Functions#

  • Functions have no intent(out) or intent(inout) dummy variables.

  • Functions without side effects should be declared pure.

  • Possible specifications of return value

    • real(pReal) | integer [pure] function f(...)

    • [pure] function f(...) result (res)

  • Variable declarations follow the order

    1. intent(in)

    2. result

    3. local variables

Subroutines#

  • Subroutines without side effects should be declared pure.

  • Subroutine dummy arguments are sorted

    1. intent(out)

    2. intent(inout)

    3. intent(in)

  • Variable declarations follow the order

    1. intent(in)

    2. intent(inout)

    3. intent(out)

    4. local variables

Naming Scheme#

  • Global variables are prefixed by the name of the module.

  • Parameters are written in CAPITALS.

Common Variable Names#

  • ho: homogenization ID

  • ph: phase ID

  • en: entry

  • ce: cell

  • co: constituent

  • el: element

  • ip: integration point

Indentation and Line Format#

  • No indentation for modules/programs and functions/subroutines.

  • Two spaces (no tab stops) per each additional level.

  • Line should end around 100 characters; a 132 character limit is enforced.

  • OpenMP directives maintain the current indentation level.

Code Documentation#

  • Functions, variables, and parameters are described by doxygen tags.

  • Readable code (e.g. explanative variable names) is preferred over in-line comments.

Recommendations#

  • Nested control structures (do, if, where, or select case) should be named.

    IncLooping: do i = 1_pInt, 10_pInt
      subIncLooping: do s = 1_pInt, 1000_pInt
        a = a + time(i,s)
      end do subIncLooping
      a = 1/a
    end do IncLooping
    

    instead of

    do i = 1_pInt, 10_pInt
      do s = 1_pInt, 1000_pInt
        a = a + time(i,s)
      end do
      a = 1/a
    end do
    
  • Field initialization with spread is preferred over explicit loops.

    real(pReal), dimension(3,3,10) :: a
    
    a = spread(math_I3,3,10)
    

    instead of

    real(pReal), dimension(3,3,10) :: a
    
    a = 0.0_pReal
    do i = 1_pInt, 10_pInt
      a(1:3,1:3,i) = math_I3
    end do
    
  • Calculations over entire fields should use intrinsic functions (such as sum or prod) instead of explicit loops.

    real(pReal), dimension(3,3,10) :: a
    real(pReal), dimension(3,3)    :: b
    
    b = sum(a)
    

    instead of

    real(pReal), dimension(3,3,10) :: a
    real(pReal), dimension(3,3)    :: b
    
    b = 0.0_pReal
    do i = 1_pInt, 10_pInt
      b = b + a(1:3,1:3,i)
    end do
    
  • Explicit range specifications are preferred over assumed size/shape.

    integer(pInt), dimension(3,3,5,5) :: field
    integer(pInt), dimension(3,3)     :: tensor
    
    field(1:3,1:3,1,1) = tensor
    

    instead of

    integer(pInt), dimension(3,3,5,5) :: field
    integer(pInt), dimension(3,3)     :: tensor
    
    field(:,:,1,1) = tensor
    

Resources#

Python#