Octupus uses the C preprocessor to extend the capabilities of Fortran 90. The reason for using a C preprocessor and not a Fortran one is that it is quite standard and all machines have one. For some technical details on what preprocessors are acceptable for this purpose, see Preprocessors.
Each octopus source code file in src/ should include the header global.h and use the global_m module.
To be able to change at compile time the size of the real type, the macro FLOAT is defined, this must be used instead of any fortran native real type. To define literals of this type the macro CNST should be used. The most common values are also defined in the global_m module: M_ONE, M_TWO, ... , M_TEN, M_HALF, M_THIRD , M_FOURTH, M_TWO_THIRD, M_Pi, etc.
FLOAT :: a, b a = M_FIVE b = CNST(27.211383)
For complex values, use the macro CMPLX.
If you need types of a given precision, you can use REAL_SINGLE and REAL_DOUBLE, which are always defined as 4 bytes and 8 bytes values respectively.
|MAX_DIM||Maximum number of dimensions that the code can use.|
Poor men's templates
To avoid writing the same piece of code for complex and real functions, we have a series of macros that allows us to write generic functions (or templates) that can be defined for different datatypes at compile time.
The macros come in the files "real.F90" and "complex.F90" (there is also "integer.F90" but this one is seldomly used). There is also a file called "undef.F90" that undefines the macros so they can be defined again. The typical way to generate the code is by including the template subroutines in a file with "_inc.F90" extension and include it twice in the parent file with different macro definitions. For example this is from mesh_function.F90:
#include "undef.F90" #include "real.F90" #include "mesh_function_inc.F90" #include "undef.F90" #include "complex.F90" #include "mesh_function_inc.F90"
In the included file you can write generic code by using some macros. The most important macro R_TYPE is defined to take the value FLOAT or CMPLX. To be able differentiate the name of functions or variables use the
X() macro, it appends
d to the argument for real values and
z for complex. So for example the line
call X(hpsi)(h, gr, st%X(psi)(:,:, p, ik), h_psi, ik)
line would go into
call dhpsi(h, gr, st%dpsi(:,:, p, ik), h_psi, ik)
call zhpsi(h, gr, st%zpsi(:,:, p, ik), h_psi, ik)
. The R_MPITYPE macro contains the appropiate MPI_DATATYPE value to perform parallel operations with the R_TYPE type.