Skip to content

Please consider updating to Fortran 2018 #7

@rouson

Description

@rouson

Numerous aspects of the coding style and structure in this repository are archaic. There have been four revisions of the Fortran standard in the three decades since Fortran 90 and two revisions of the MPI standard in the more than two decades since MPI-1. Exploiting newer Fortran standards could make FEST-3D code more clear, more concise, potentially more robust, and might even aid performance.

The list of updates I could suggest grows with every file I open so the following list is far from exhaustive:

  1. Declarations such as integer(kind=4) are not portable across compilers and not even guaranteed to be the same for the same compiler across different platforms or different compiler versions. If a specific precision is desired, the selected_int_kind() function is the preferred method. If a specific width in memory is desired, the more recent standards provide several kind parameters that can be accessed via use association (e.g., use iso_fortran_env, only : int32).

  2. In many places, nested loops could be collapsed to a single line using an array statement. Besides the benefits in clarity and conciseness some compilers actually optimize array statements better than do loops. This stems partly from the fact that do loops are inherently serial even though compilers might choose to vectorize the loops at high levels of optimization. Array statements have been available since Fortran 90. On a related note, I recommend reviewing modern Fortran's rich set of intrinsic functions for manipulating arrays (merge, pack, findloc, etc.). These functions can often be used to collapse multiple statements into one and might perform better by letting the compiler choose the underlying algorithm.

  3. Many loops that can't be converted to array statements can be made concurrent. This both has potential performance benefits (again because it doesn't impose unnecessary ordering of loop iterations) and it makes nested loops more concise because they can be collapsed with a syntax such as do concurrent( i=1:nx, j=1:ny, k=1:nz). Do concurrent has been available since Fortran 2008.

  4. Building MPICH with gfortran version 9 or higher installs the mpif08 module that provides a more modern interface to MPI, starting with using use mpif08 rather than accessing MPI via #include. Despite the module name, this actually uses a feature set that entered the language in Fortran 2018.

  5. Fortran 2003 added support for deferred-length character variables declared as characer(len=:), allocatable :: string, obviating the need for fixed-length character variables in many places.

  6. Even since Fortran 90, the language has supported derived types, which can be used to package related data and thereby reduce the length of argument lists.

  7. What is most shocking, however, is the number of subroutines in FEST-3D that have no arguments. This combined with the long lists of use statements suggests that a great number of the variables are widely accessed outside the module in which they are declared. This coding style can quite easily lead to a difficult-to-decipher interconnectedness of data dependancies that are truly daunting for anyone new to the code.

  8. This code has dozens of explicit deallocate statements. Are these necessary? If the memory was allocated via an allocatable variable, then the compiler is obligated to free the memory when the variable goes out of scope. In general, it's best to let the compiler do it's job unless you have data demonstrating that your explicit deallocation improves performance or significantly reduces the overall memory footprint. (Even if you deallocate memory, I don't think the compiler is obligated to return the memory to the operating system until the program ends anyway.)

  9. This code makes considerable use of pointer variables. Any large Fortran project that makes extensive use of pointer variables should articulate a very clear policy for how the pointer variables are to be used, including how the project will avoid memory leaks and dangling pointers. In almost all circumstances, if a pointer is being used to allocate memory, for example, it should be replaced by an allocatable variable (scalar or array) and a reference-counting scheme should be incorporated and enforced. It appears that the target variables in FEST-3D are all allocatable arrays. Given that you're doing explicit deallocations, what is your strategy for ensuring that no pointer is ever associated with a deallocated or unallocated array? Extensive use of pointer variables raises many questions that should be addressed thoroughly in documentation.

  10. Lastly, I'm very curious about your choice to use two-sided blocking MPI_Send and MPI_Recv. Is there a reason for not using non-blocking MPI_Isend and MPI_IRecv? More importantly, why use MPI at all in a new project? Fortran has been parallel since the 2008 standard and gfortran supports all Fortran 2008 parallel features as well as most Fortran 2018 parallel features. The gfortran parallel runtime library (OpenCoarrays) uses the newer one-sided MPI-3 MPI_Put and MPI_Get, which can outperform even non-blocking MPI in some applications. So besides not having to write your own MPI, you'll get more advanced MPI on the back-end if you let the compiler and runtime library generate the MPI calls for you.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions