Fortran style guide for Phantom
Unsure how to format your routine? How many spaces to indent? Want to make your code fit in with the rest of Phantom? We present the Phantom f90 style guide…
Conventions which are enforced by the nightly bots
You can run the bots yourself as follows:
cd phantom/scripts
./bots.sh --apply
Indentation
Indentation is enforced automatically by the indent-bot, which uses the findent tool. The specific command used to indent the code is:
findent -r1 -m1 -c3 -Rr -C- -k- -j1 < file.f90
Use modern Fortran
Do not use SHOUT CASE. THERE IS NO NEED FOR SHOUTING.
endif, enddo
Use endif and enddo, not end if or end do:
if (blah) then
...
endif
not:
if (blah) then
...
end if
Conventions which are not enforced (but may be in future if we could do it safely)
if statements
Use a single space between the if and the bracket. Also use a space either side of logical operators like .and. or .or.:
if (rin >= rup .or. rin < rlow) then
not:
if(rin >= rup.or.rin < rlow) then
spacing
Use a single space either side of equals sign:
x = 3
not:
x=3
x= 3
x =3
Use a single space between type declaration and variables:
real :: x
not:
real::x
real ::x
real:: x
Do not use spaces in variable declaration lists:
real :: xmin,xmax,ymin,ymax
not:
real :: xmin, xmax, ymin, ymax
No spaces after only statements and put a single space between comma and only:
use part, only:xyzmh_ptmass,vxyz_ptmass
not:
use part, only: xyzmh_ptmass, vxyz_ptmass
use part, only : xyzmh_ptmass, vxyz_ptmass
use part, only: xyzmh_ptmass,vxyz_ptmass
use part,only:xyzmh_ptmass,vxyz_ptmass
Line continuation
Continue lines with a single ampersand at the end of the line to be continued. Do not put another ampersand at the start of the next line:
real :: x,y,z,averylongvariable,anotherlongvariable, &
b,c,d
not:
real :: x,y,z,averylongvariable,anotherlongvariable, &
& b,c,d
Variable naming conventions
Phantom adopts some variable naming conventions from older codes that influenced its development, in particular the sphNG code, which was based on the original Benz & Press code. The main one is that numbers at the end of a variable name denote the power to which the variable has been raised, with 1 indicating a power of minus one (i.e. a division):
h1 = 1./h
The square of the inverse smoothing length is thus:
h21 = h1*h1
While \(1/h^4\) is denoted:
h41 = h21*h21
Similarly, the radius squared \(r^2\) would be denoted:
r2 = x*x + y*y + z*z
You will also notice that intermediate variables (like r2) are used often in the code, this is to try to minimise repetition of expensive calculations as well as minimising memory accesses.
Finally we typically use latin indices to refer to particles, and label quantities with \(i\) or \(j\) depending on which particle it belongs to. So the radius squared of particle \(i\) would be r2i, While the same for \(j\) would be r2j, and similarly for h1i, h1j, h21i, h21j, h41i, h41j etc.
Some of this is a hangover from the days when FORTRAN (not Fortran) allowed only 5-digit variable names. In general it is better to give your variables human-readable names that make the meaning and intended use clear. Remember that 99% of development time is spent debugging, so anything that makes this easier is valuable.
Comments and docstrings
To maintain a consistent code documentation, the header-bot enforces standardised headers for each file that can act as a docstring. The header is listed right under the module/program declaration (before the variable declaration) and its format is as follows:
While a lot of these fields are automatically generated when running the bot, contributors who write new modules/programs should fill in the
DESCRIPTION
andREFERENCES
manually, as they will be generated asNone
by the bot. So before creating a pull request, run the bots with the command:You can also run the header-bot separately by adding the
--only header
flag to the command above. (to get more details on how and when to run the bots, see the section on bots in the developer guide). Once the header is generated, you can edit it to change the description and references, and then commit this new version of your file.The header-bot only runs on the first module of a file, so it is recommended to only write one module per file.
The header-bot does not run on subroutines and functions (yet), it is thus a good practice, for consistency and readability, to also include docstrings for these, on top of the regular comments throughout the code.