MESA has been developed over many years, thus there many different styles of code in use. We do not require old code to be ported to the new style. However, new code should be written following these guidelines.
In free form Fortran files, indentation is 3 spaces.
Indentation/whitespace rules are codified in an EditorConfig file located in the root of the repository (
The preferred Fortran version is at least Fortran 90 as this enables things like modules and allocatable arrays.
Common and equivalence blocks are banned. Just put the variables in a module header if needed to be shared.
When raising a number to a floating-point power, use the
pow() routine provided by
powN(x) to raise
x to an integer power
real types you should always use these for integer powers greater than 2.
**2 has so far not been a problem and is tolerated though not recommended.
auto_diff types you must use
powN for integer powers including 2.
Doing otherwise will result in a compiler error.
In general a subroutine should return as its last argument a integer
ierr which denotes whether the
subroutine succeeded or not. A value of
ierr=0 is to be used to show the subroutine succeeded,
any other value of ierr denotes an error. Any meaning in different non-zero values of
can only be determined by inspecting the subroutine that set the
The typical way to handle things is:
integer, intent(out) :: ierr ierr = 0 call my_subroutine(x,ierr) if (ierr /= 0) return
for non-critical errors.
When signalling a critical error which can not be recovered from you should use:
use utils_lib, only: mesa_error call mesa_error(__FILE__,__LINE__)
which will generate a backtrace where the error occurs, which aids in debugging. The
mesa_error can also have a optional error message:
use utils_lib, only: mesa_error call mesa_error(__FILE__,__LINE__,"An error occurred")
Do not use:
as it can become difficult to distinguish where in the code called
stop if multiple functions use
Note that the
__LINE__ macros are not expanded in
files that are included using Fortran’s
The preferred manner to declare a double precision variable is:
real(dp) :: x
double precision :: x
When using a numerical value in an expression you must make sure it is evaluated as a double. Thus use:
y1 = 1.1d0 * x ! or y2 = 1.1_dp * x
Do not leave values as a bare float:
y3 = 1.1 * x
1.1 gets interpreted as a single precision value, and will lead
y3 to have a different value
OMP critical blocks¶
OMP critical blocks allow the programmer to specify that a section of code should only be executed by one thread at a time. They can also be given a name:
!$omp critical my_block
and this name should differ from any other code entities (e.g. subroutines).
Each named critical block will be executed by one thread at a time. Different named critical blocks can be executed at the same time. However, all unnamed critical blocks act like one block and thus can not be executed in parallel. Therefore you should always named your OMP critical blocks to ensure the best performance.
Do not name your OMP critical block with a name that has already been used for a variable, procedure, module or any other object.
Use explicit formats for any
write statements. Different compilers use different default formats, which can lead to spurious
failures when strings are compared. e.g. when printing some floating point number
x, instead of
write(*, '(1pd26.16)') x
Unformatted statements are likely to cause unit tests to fail. They also make it difficult to compare output from runs with different compilers.
Some helpful formats are provided in
Should be avoided when the variables that are strings. This is because if the string contains a / (forward-slash) then when doing a unformatted read Fortran will stop reading the line.
Either build a full format statement or read the line into one string and split on whitespace. There is also a function
utils_lib.f90 that can be used to split a line up based on whitespace.
const module defines many commonly used mathematical
pi) and physical constants (e.g.
hbar), which should be
used for consistency across the code. This includes simple fractions
one_third) and simple functions of mathematical constants
pi4 = 4*pi).
Constants should be added to
const_def.f90 if they meet any of the following criteria:
- If it is a well known mathematical or physical constant or derived from other well known constants
- If other code might use the constant
If making a new environment variable then the variable should be prefixed with
MESA_ to ensure we don’t collide with other variables.