Using Fortran Modules#

This guide explains how to organise your Abaqus user subroutine code using Fortran modules.

About Fortran Modules#

Fortran modules contain definitions that are made accessible to programs, procedures, and other modules through the use statement. They can contain parameters, variables, type definitions, procedures, and interfaces.

Placing variables and procedures into modules has several important benefits:

  1. Modules provide a scoped namespace for related variables and procedures which have to be explicitly imported

  2. Modules automatically generate explicit interfaces which are required for modern procedures and which allow for better compile-time error detection

  3. Modules can be used to logical organise code by collecting related procedures and variables together in the same module

  4. Module code can be easily reused and combined by other subroutines without duplication

Recommendation

It is strongly recommended that all auxilliary procedures and shared variables are stored in modules.

Rationale Modules enable the use of modern Fortran features and provide automatic compile-time checking of procedure interfaces.

Module variables are shared but do not suffer from the same problems as common block variables.

Further Recommendations

Modularising your User Subroutine#

Modularising a user subroutine entails breaking it up into functions or subroutines, and storing these in one or more modules where each module is kept in a separate source file.

Note

The examples in this guide will use free-form Fortran and explicit typing. You can read more about these in the linked guides, however they are not prerequisites to understand this guide.

We will consider a simple example, where we only have one Fortran module. In this case we will have two Fortran source files:

  1. The main user subroutine file: this is the top-level file that gets passed to Abaqus with user=<file>. It only contains the user subroutine interface, which calls procedures in our module.

  2. The Fortran module file: this source file contains a Fortran module where we will place all the functionality of our user subroutine broken up into functions and subroutines.

In this example we will call these usub.f and elastic_mod.f respectively.

Important

All source files should be placed in the same folder. It is convention to call this folder src

See also

See the sample repository on Github which gives a complete working example of the concepts presented in this guide.

usub.f#

 1!DIR$ FREEFORM
 2#include 'elastic_mod.f'
 3
 4subroutine umat(stress,statev,ddsdde,sse,spd,scd, &
 5  rpl,ddsddt,drplde,drpldt, &
 6  stran,dstran,time,dtime,temp,dtemp,predef,dpred,cmname, &
 7  ndi,nshr,ntens,nstatv,props,nprops,coords,drot,pnewdt, &
 8  celent,dfgrd0,dfgrd1,noel,npt,layer,kspt,jstep,kinc)
 9
10  use iso_fortran_env, only: dp=>real64
11  use elastic_mod, only: get_properties, plane_strain_jacobian, &
12                         update_stress
13  implicit none
14
15  real(dp), intent(inout) :: stress(ntens), statev(nstatv), ddsdde(ntens,ntens)
16  real(dp), intent(inout) :: sse, spd, scd, rpl, ddsddt(ntens), drplde(ntens)
17  real(dp), intent(inout) :: drpldt
18  real(dp), intent(in) :: stran(ntens), dstran(ntens), time(2), dtime, temp
19  real(dp), intent(in) :: dtemp, predef(1), dpred(1)
20  character(len=80), intent(in) :: cmname
21  integer, intent(in) :: ndi, nshr, ntens, nstatv, nprops
22  real(dp), intent(in) :: props(nprops), coords(3), drot(3, 3), pnewdt
23  real(dp), intent(in) :: celent, dfgrd0(3,3), dfgrd1(3,3)
24  integer, intent(in) :: noel, npt, layer, kspt, jstep(4), kinc
25  
26  real(wp) :: e,xnu
27  integer i,j
28
29  call get_properties(props, e, xnu)
30
31  call plane_stress_jacobian(ddsdde,e,xnu)
32
33  call update_stress(dstran,ddsdde,stress)
34
35end subroutine umat

Note how the top-level user subroutine does very little itself, but rather all the functionality has been organised into subroutines that are contained within the module elastic_mod.f.

There are two important steps required to access the subroutines defined in the module:

  1. Line 2 : include the module source – We must include the module source file at the top of our main user subroutine file in order for it to be compiled when Abaqus is run.

    • With multiple modules, the source files must be included in the correct order, whereby modules are included before other modules that use them

    • The module files should only be included in the top-level user-subroutine file, and not in other module files; this is to avoid accidently including the same module more than once

    • We use the preprocessor syntax #include, instead of include, since this allows us to easily generate a single self-contained source file by running the preprocessor

  2. Line 11 : use the module to access its members – We must add a use statement to any module, subroutine or function that needs to access the contents of the module. Here we also specify which subroutines we are going to use from the module.

Some other points to note about this code:

elastic_mod.f#

 1!DIR$ FREEFORM
 2module elastic_mod
 3  use iso_fortran_env, only: dp=>real64
 4  implicit none
 5
 6  contains
 7
 8  subroutine get_properties(props, e, xnu)
 9    real(dp), intent(in) :: props(:)
10    real(dp), intent(out) : e, xnu
11
12    e = props(1)
13    xnu = props(2)
14  end subroutine get_properties
15
16  subroutine plane_stress_jacobian(ddsdde,e,xnu)
17    real(dp), intent(out) :: ddsdde(:,:)
18    real(dp), intent(in) :: e, xnu
19
20    ddsdde(1,1) = 1.d0
21    ddsdde(1,2) = xnu
22    ddsdde(2,1) = xnu
23    ddsdde(2,2) = 1.d0
24    ddsdde(3,3) = 0.5d0*(1.d0-xnu)
25    ddsdde = ddsdde*e/( (1.d0+xnu*xnu) )
26  end subroutine plane_stress_jacobian
27
28  subroutine update_stress(dstran,ddsdde,stress)
29    real(dp), intent(in) :: dstran(:)
30    real(dp), intent(in) :: ddsdde(:,:)
31    real(dp), intent(out) :: stress(:)
32    
33    do i = 1,size(ddsdde,1)
34      do j = 1,size(ddsdde,2)
35        stress(i) = stress(i) + ddsdde(i,j)*dstran(j)
36      end do
37    end do
38  end subroutine update_stress
39
40end module elastic_mod
41!DIR$ NOFREEFORM
42!DIR$ FIXEDFORMLINESIZE:132

This file contains our module definition (called elastic_mod) and all the subroutines that we call in the top-level user-subroutine file.

  • Line 3 : the double precision dp parameter is accesible to all subroutines in the module

  • Line 4 : everything in this module is explicitly typed (see explicit typing with Abaqus)

  • Note how we don’t have to pass in the size of each arrays as separate arguments - this is one advantage of using module files, which is that they enable the use of assumed-shape array arguments[1]

  • This excerpt is cut-down for brevity; the Fortran Code Guidelines would recommend extra line spacing for readability, as well as some comments to describe each subroutine and their arguments.

Running Abaqus with Modular Code#

Running Abaqus with modularised code is no different to normal, simply make sure that the user subroutine file and the module files are in the same folder and pass the top-level (non-module) source file to Abaqus.

Recommendation

It is a good idea to copy source files to the job folder when running Abaqus jobs. This means that you always know which version of the code produced which set of results; this is important when evaluating the effect of code changes.

If the source files are in the same folder as a job file job.inp then, using the example above, you would run Abaqus with:

abaqus job=job.inp user=usub.f double interactive

There is no need to list the module files for Abaqus since they are specified with the #include statements at the top of usub.f.

Generating a Single-Source Version#

If you require a self-contained single-source file to distribute, you can generate one by invoking the Intel Fortran preprocessor at the command line.

First navigate to the directory containing your source files in your command window, then run the following command:

ifort -EP usub.f > usub_single.f

This will output usub_single.f which contains all the code, including the modules, in one file.

Caution

For this single-source command to work, make sure that you use the #include syntax to include the modules and not include.