EUROPEAN ORGANIZATION FOR NUCLEAR RESEARCH
Rules for Fortran routines for MAD-X
- Code
- lower case throughout
- all routines start with ``implicit none''
- the following types should be used exclusively:
- integer - use integer as well instead of logical, 0 = false,
else true
- double precision (not real*8)
- complex*16 - only internally, and in cases where it really helps
- character - if this routine can be called from outside
(i.e. as well from C routines), always foresee a length input
variable (see example). When calling a C routine with character strings,
make sure they end with a blank (e.g. 'abc ').
- use only generic names for functions, i.e. sin, cos, abs, exp
etc. and not dsin, dcos, dabs, dexp etc.; nota bene: ANSI
for arcus sinus and arcus cosinus is asin and acos (not arsin and arcos)
- do not use statement functions, arithmetic IF (3-branch), or IMPLICIT GOTO.
- in DO loops: use always do...enddo constructs.
- IMPORTANT: when transferring strings to C routines, always terminate
the string with a blank, e.g.
call double_to_table('twiss ', 'betx ', betx)
- When transferring integer or double to C routines, always use
specific variables (no values or expressions), e.g. to receive the
current element name
integer i
character * 16 name
i = 16
call element_name(name, i)
- Style
- all modules and stand-alone routines perform all input/output
through symbolic variables in the call (no ``common'');
common blocks can be used inside modules, however.
- functions return only one (the function-) value and do not
modify any of the input variables
- all input/output parameters are described, and the routine
purpose stated
- avoid ``goto'' as far as reasonable
- indent do ... enddo and if ... then ... else constructs
- avoid using ``return'';
only one exit of the routine, at the end (this makes
debugging easier)
- no I/O (read, write, print to files) in a Fortran routine, except
for printing to output (error messages, summary data etc.);
most of the data will be put into tables via C routine calls.
- Error flags, or calls to special exception routines
can be foreseen as need arises.
- General
- for local buffers of moderate size use local arrays; for bulk
storage use blank common; blank common may as well be used to
pass data inside modules
- for matrix manipulation use the existing m66 package
- do not use any external library (e.g. cernlib), rather extract
and include the code needed
- Checks are essential!!
- Run your code through f2c to check that the Fortran is compatible
with standard Fortran 77. Recent testing of the MAD-X Fortran77 code has
revealed some problematic programming techniques.
Example: f2c twiss.F
- Use the NAG f95 compiler with very strict checking by using
"make -f Makefile_develop (madxp)" in brackets if you test the MAD-X
PTC version.
- Then run your example with that executable. The "-nan" compile
flags will demonstrate at run time if variables have not been
properly initialized so as to allow for fixing this problem.
- At last the MAD-X custodian (presently FS) will check the
compatibility with Fortran90. Thereby performing certain
"beautification" procedures. Moreover, the NAG f95 compiler
reveals more inconsistencies in the Fortran90 mode.
Example
integer function type(s_length, s_type)
*++ Purpose: returns an integer type code for certain elements
*-- input:
* s_length length of s_type
* s_type string containing type
*-- return values:
* 1 for s_type == 'drift'
* 2 for s_type == 'sbend'
* 3 for s_type == 'rbend'
* 5 for s-type == 'quadrupole'
* 0 else
*++
implicit none
integer s_length
character *(*) s_type
if (s_type(:s_length) .eq. 'drift') then
type = 1
elseif (s_type(:s_length) .eq. 'sbend') then
type = 2
elseif (s_type(:s_length) .eq. 'rbend') then
type = 3
elseif (s_type(:s_length) .eq. 'quadrupole') then
type = 5
else
type = 0
endif
end
Hans Grote
2001-01-22