Thursday, August 02, 2007

Notes Fortran

NotesFortran

Contents
=========

FORTRAN95 features
!DEC$ - compiler Directives
Keyword - SEQUENCE
Keyword - PURE
Initialize Data with slash /
Subroutines passed as argument of another subroutine
Allocatable Pointers / Array of Pointers
Using pointers in procedures
Dynamic Memory Allocation with Pointers
Declaration Statements for Arrays
Derived Data Types - with pointer components and being used as dummy pointer arguments
OpenMP
Static, Stack, Heap
Converting Integer to Character OR Writing to variable
Handling Character Strings between C# and Fortran
OpenMP programming warnings
Fortran Editors
String Manipulation



FORTRAN95 features
===================
List of F95 features implemented in Intel Fortran

1. FORALL -
2. PURE - for safety - ensure only INTENT(OUT,INOUT) arguments are changed.
3. ELEMENTAL - a type of PURE routine. Allow operation of arrays on element level.
4. CPU_TIME -
5. NULL intrinsic function - allow allocatable arrays to be pointed to this.


!DEC$ - compiler Directives
============================
Compaq (Digital) Visual Fortran (http://www.canaimasoft.com/f90vb/onlinemanuals/usermanual/TH_60.htm)


Compaq's Visual Fortran compiler (CVF) offers a great deal of flexibility to
create DLLs callable from C and/or Visual Basic. The compiler has a good set of
options to modify name-mangling, calling conventions and the method used to pass
arguments. Most of these options can be indicated through the use of compiler
directives (or pragmas) embedded in the source code. CVF compiler directives are
defined as comment lines, starting with DEC$.


To indicate that a subroutine should conform to the standard calling convention,
you add the DEC$ATTRIBUTE STDCALL compiler directive to the declaration of the
subroutine. For example:


subroutine MySub(argument1, argument2)  
   !DEC$ATTRIBUTES STDCALL:: GenDNASequence

In Compaq Visual Fortran, adding the STDCALL attribute also changes the default
method used to pass arguments, so you need to tell the compiler that arguments to
subroutine MySub are passed by reference. You can do this with the
DEC$ATTRIBUTE REFERENCE directive:

subroutine MySub(argument1, argument2)
!DEC$ATTRIBUTES STDCALL:: MySub
!DEC$ATTRIBUTES REFERENCE:: argument1, argument2


Also, when a procedure is declared with the standard calling convention (STDCALL),
Compaq Visual Fortran mangles its name. The name-mangling performed by CVF converts
the name of the procedure to all uppercase, adds an underscore as a prefix to the name,
and appends an at symbol (@) followed by the size of the stack (in bytes) at the end of
the name. The size of the stack is equal to 4 times the number of arguments in the
subroutine. MySub has 2 arguments, so the mangled name will be:


_MYSUB@8


Having to use this name to call our DLL procedure would be awful in most languages,
and illegal in Visual Basic. You can use another DEC$ATTRIBUTES compiler directive to
indicate an alias for the mangled name of the exported subroutine:



!DEC$ATTRIBUTES ALIAS: 'MySub'::MySub



The first argument is the alias (i.e. the name by which the subroutine would be available
to external programs using the DLL), the second argument is the Fortran name of the subroutine.



Finally, to indicate that the subroutine must be exported to the DLL as a public procedure,
you add the DEC$ATTRIBUTES DLLEXPORT compiler directive to the body of the subroutine:

!DEC$ATTRIBUTES DLLEXPORT:: MySub

So the full declaration of MySub would look like this:

subroutine MySub(argument1, argument2)
!DEC$ATTRIBUTES STDCALL:: MySub
!DEC$ATTRIBUTES DLLEXPORT:: MySub
!DEC$ATTRIBUTES ALIAS: 'MySub'::MySub
!DEC$ATTRIBUTES REFERENCE:: argument1, argument2



To create a DLL, you compile and link using the /dll switch. The following command-line
would compile and link MySub.f90 (containing subroutine MySub) into MySub.dll:


f90 MySub.f90 /dll /out:MySub.dll


Keyword - SEQUENCE
===================
SEQUENCE cause the components of the derived type to be stored in the same sequence they are
listed in the type definition. If SEQUENCE is specified, all derived types specified in component
definitions must be sequence types.


Keyword - PURE
===================
Pure Procedures
A pure procedure is a user-defined procedure that is specified by using the prefix PURE (or
ELEMENTAL) in a FUNCTION or SUBROUTINE statement. Pure procedures are a feature of
Fortran 95.
A pure procedure has no side effects. It has no effect on the state of the program, except for the
following:    
• For functions: It returns a value.
• For subroutines: It modifies INTENT(OUT) and INTENT(INOUT) parameters.
The following intrinsic procedures are implicitly pure:    
• All intrinsic functions  
• The elemental intrinsic subroutine MVBITS
• The intrinsic subroutine MOVE_ALLOC
A statement function is pure only if all functions that it references are pure.



Initialize Data with slash /
==============================
Variables are not auto-initialized. To initialize a variable as you declare it,
put the initial value between two slashes. This kind of initialization is done once
when the unit is first loaded, and hence, it should not be used in a subprogram that
gets invoked repeatedly (use an assignment instead). For symbolic constants,
initialization is achieved via the parameter statement.

    character title*20 / 'York' /
    integer*2 count / 0 /
    real*4 amount / 1.0 /
    !---------------------------------------------------
    ! Note that title will have 20 characters even though
    ! we stored only 4 (they will be padded by blanks).


Subroutines passed as argument of another subroutine
======================================================
subroutine subA( subB )

The subroutine named subB needs to be declared EXTERNAL and hence not be in a module.
If a function needs to be in the same module then can be done as follows:

module test
  contains
     subroutine subA(subB)
external subB
     .....
     subroutine subC()
end module
subroutine subB()
   use test
   call subC()
end subroutine


Allocatable Pointers / Array of Pointers
=========================================
REF: Fortran 90/95 for Scientists and Engineers, Stephen J Chapman
1. It is illegal to have array pointers of native data types in Fortran:
   REAL, DIMENSION(:), POINTER :: PTR
   - the dimension attribute refers to the pointer's target, not of the pointer.
   - the dimension must be deffered shape and the size is the size of the target, not
     the pointer.
2. It is legal to have array pointers by using derived data types:
  TYPE :: ptr
     REAL, DIMENSION(:), POINTER :: P
  END TYPE
  TYPE(ptr), DIMENSION(3) :: P1

REF: Intel Fortran Language Reference
1. In contrast to allocatable arrays, a pointer can be allocated a new target even if it is currently associated with target. The previous association is broken and the pointer is then associated with the new target.
2. If the previous target was created by allocation, it becomes inaccessible unless it can still be referred to by other pointers that are currently associated with it.


Using pointers in procedures
===============================
Pointers may be used as dummy arguments in procedures and may be passed as actual arguments to procedures.
1. If a procedure has dummy arguments with either POINTER or TARGET attributes, then the procedure must have an explicit interface.
2. if a dummy argument is a pointer, then the actual argument passed to the procedure must be a pointer of the same type, kind and rank.
3. a pointer dummy argument must not have the intent attribute
4. a dummy argument cannot appear in an ELEMENTAL procedure in Fortran95.


Dynamic Memory Allocation with Pointers
========================================
REF: Fortran 90/95 for Scientists and Engineers, Stephen J Chapman

REAL, DIMENSION(:), POINTER :: ptr1
ALLOCATE (ptr1(1:10))

This statement creates an unnamed data object of the specified size and the pointer's type and sets the pointer to point to the object. Because the new data object is unnamed, it can only be accessed by using the pointer. After the statement is executed, the association status of the pointer becomes associated. If the pointer was associated with another data object before the ALLOCATE statement is executed, then that association is lost.

The data object created by using the pointer ALLOCATE statement is unnamed and so can only be accessed by the pointer. If all pointers to that memory are either nullified or reassociated, with other targets, then the data object is no longer accessible by the program. The object is still present in memory, but it is no longer possible to use it => MEMORY LEAK.

If a piece of allicated memory is deallocated, then all pointers to that memory should be nullified or reassigned. One of them is automatically nullified by the DEALLOCATE statement, and any others should be nullified in NULLIFY statements.

Declaration Statements for Arrays
===================================
SUBROUTINE SUB(N,C,D,Z)
   REAL, DIMENSION(N,15) :: IARRY        !explicit shape array
   REAL, C(:), D(0:)                     !assumed shape array
   REAL, POINTER :: B(:,:)               !deferred shape array pointer
   REAL, ALLOCATABLE, DIMENSION(:) :: K  !deferred shape allocatable array
   REAL :: Z(N,*)                        !assumed size array

Automatic Arrays - local array in a function, whose size is one of the arguments
Adjustable Arrays - array which is an argument, whose size is also one of the arguments.

To use arrays efficiently, see Optimizing Applications -> Programming Guidelines -> Using Arrays Efficiently.
When passing arrays as arguments, either the starting (base) address of the array or the address of an
array descriptor is passed:
When using explicit-shape (or assumed-size) arrays to receive an array,
the starting address of the array is passed.

When using deferred-shape or assumed-shape arrays to receive an array,
the address of the array descriptor is passed (the compiler creates the array descriptor).

Automatic vs Save
Automatic variables can reduce memory use because only the variables currently being used are allocated to memory.

By default, the compiler allocates local variables of non-recursive subprograms, except for
allocatable arrays, in the static storage area. The compiler may choose to allocate a variable in
temporary (stack or register) storage if it notices that the variable is always defined before
use. Appropriate use of the SAVE attribute can prevent compiler warnings if a variable is used
before it is defined.




Derived Data Types - with pointer components and being used as dummy pointer arguments
========================================================================================
Given a derived data type with pointer arguments:
   type varDDT
      type(BigDDT), pointer :: rComp
   end type
Given that it is used as a dummy pointer argument
   subroutine foo(aDDT)
      type(varDDT), pointer :: aDDT
 ....
    end subroutine

Then, in another function which uses "foo", the DDT can be used as:
program
  type(varDDT), pointer :: aDDT_p
  type(varDDT) :: vDDT

  call testFoo(vDDT)   ! vDDT contains the data found in testFoo
  nullify(aDDT_p)
    end program

    subroutine testFoo(vDDT_local)
  type(varDDT) :: vDDT_local
       aDDT_p => vDDT_local

  call foo(aDDT_p)
       ! vDDT_local will be able to pass to outside routine safely.
    end subroutine


Note that this method is not required if the DDT concerned does not contain components
which are also DDT.


OpenMP
=======

Prerequisite:
Before inserting any OpenMP parallel directives, verify that your code is safe for parallel execution by doing the following:

Place local variables on the stack. This is the default behavior of the Intel Fortran Compiler when -openmp is used.

Use -automatic (or -auto_scalar) to make the locals automatic. This is the default behavior of the Intel Fortran Compiler when -openmp is used. Avoid using the -save option, which inhibits stack allocation of local variables. By default, automatic local scalar variables become shared across threads, so you may need to add synchronization code to ensure proper access by threads.

Static, Stack, Heap
====================
Heap area stores dynamic arrays
Static storage area store variables that are available for the life time of the program.
In C, local variables are stored in the stack.

In Fortran,
"By default, the compiler allocates local scalar variables on the stack. Other, non-allocatable variables of non-recursive subprograms are allocated in static storage by default. This default can be changed through compiler options. Appropriate use of the SAVE attribute may be required if your program assumes that local variables retain their definition across subprogram calls."

For openMP, local variables in Fortran will become automatic and thus stored in the stack. Note that
OpenMP threading model is based on threads and each has its own stack.



"static" as a descriptive term refers to the lifetime of C++ memory or storage locations. There are several types of storage:
        - static
        - dynamic (heap)
        - auto (stack)
A typical storage layout scheme will have the following arrangement, from lowest to highest virtual memory address:
        text (program code)
        static (initialized and uninitialized data)
        heap
        (large virtual address space gap)
        stack
with the heap and stack growing toward each other. The C++ draft standard does not mandate this arrangement, and this example is only an illustration of one way of doing it.


heap-array in Intel Fortran - This option puts automatic arrays and arrays created for temporary computations on the heap instead of the stack.
on Windows:
    /heap-arrays-        = no heap arrays (default)
    /heap-arrays[:size]  = where arrays of size (in kb) or larger are put on the heap.
on Linux:
    -no-heap-arrays        = no heap arrays (default)
    -heap-arrays [size]    = where arrays of size (in kb) or larger are put on the heap.
Example:
    In Fortran, an automatic array gets it size from a run-time expression. For example:
RECURSIVE SUBROUTINE F( N )
INTEGER :: N
REAL :: X ( N )     ! an automatic array
REAL :: Y ( 1000 )  ! an explicit-shape local array on the stack Array X in the example above
                    ! is affected by the heap-array option. Array Y is not.





Converting Integer to Character OR Writing to variable
========================================================
Example:
   CHARACTER(LEN=15), ALLOCATABLE  :: cPctile(:)
   ALLOCATE( cPctile(nPctile) )
   write(cPctile(jj), '(F15.7)') pctile(jj)

The number in pctile(jj) is being written into a CHARACTER variable called cPctile. Note the character has length of
15 which is enough to write 15 characters specified by the Format F15.7.



Handling Character Strings between C# and FortranSubmit New Article
Last Modified On :   December 6, 2009 6:09 PM PST
Rate Please login to rate! Current Score: 0 out of 0 usersPlease login to rate! Current Score: 0 out of 0 usersPlease login to rate! Current Score: 0 out of 0 usersPlease login to rate! Current Score: 0 out of 0 usersPlease login to rate! Current Score: 0 out of 0 users






Handling Character Strings between C# and Fortran
=================================================================

Passing Character Strings as In parameters from C# to Fortran

C# provides built-in reference type "string" representing a string of Unicode characters. It is an alias for String in the .NET Framework. When passing "string" type by value from C# to Fortran function or subroutine platform invoke service copies string parameters, converting them from the .NET Framework format (Unicode) to the unmanaged format (ANSI), if needed. The unmanaged format is null-terminated so the C# method prototype of Fortran function or subroutine must account for the length argument passed along with the string address.


Passing Strings as In/Out parameters from C# to Fortran

Managed strings are immutable, platform invoke does not copy them back from unmanaged memory to managed memory when the function returns. If the Fortran function or subroutine wants In/Out parameters you need use StringBuilder Class in C#. StringBuilder Class represents a string-like object whose value is a mutable sequence of characters.

Fortran subroutine
subroutine FPassStringSub (Int_Arg, Str_In, Str_Out)
!DEC$ ATTRIBUTES DLLEXPORT :: FPassStringSub
integer, intent(in) :: Int_Arg
character*(*), intent(in) :: Str_In
character*(*), intent(out) :: Str_Out
end subroutine



C# method prototype
        [DllImport("FDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FPASSSTRINGSUB(ref int Int_Arg, string Str_In, StringBuilder Str_Out, int Str_In_Len, int Str_Out_Len);
STR_IN_LEN, int STR_OUT_LEN);



Returning Character Data Types from Fortran to C#

Similar to how C language handles Fortran function returning character data type the corresponding C# method prototype must add two additional arguments to the beginning of the argument list:
-  The first argument is a StringBuilder object where the called function should store the result.
-  The second argument is an int value showing the maximum number of characters that must be returned, padded with blank spaces if necessary.


Fortran function

function FRetString(Int_Arg)
!DEC$ ATTRIBUTES DLLEXPORT :: FRetString
character(*) :: FRetString
integer, intent(in) :: Int_Arg
end function


C# method prototype
        [DllImport("FDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FRETSTRING(StringBuilder Str_Result, int Res_Len, ref int Int_Arg);



How to avoid Race Conditions in OpenMP programming
===================================================
This section aims to cover a few points to watch for when doing parallel programming using OpenMP in Fortran.
The tips here could also apply to different languages with OpenMP such as C/C++.
1. First danger sign of parallel programming bug is inconsistent behaviour.
2. When a program stalls or hangs indefinitely sometimes, but other times run to completion.
3. When a program crashes sometimes, but other times run to completion.
4. When OpenMP is applied to a higher level function that calls many small low level functions, check  whether module variables have SAVE attribute.
5. If module variables have save attributes, then check if those variables can be declared PRIVATE too so that no outside functions can use them.
6. When the SAVE module variables are being altered in a function in the module, check to see if the function can be encapsulated in a OMP parallel region.
7. When checking for race conditions using tools like Intel Thread Checker, ensure that the number of threads specified is not greater than the number of processors / cores.


Fortran Editors
=================

The following list are GUI based Fortran editors development environment.

Force
http://force.lepsch.com/

Plato - for Silverforst FTN95
http://www.silverfrost.com/16/ftn95/plato.aspx

Photran - on Eclipse IDE
http://www.eclipse.org/photran/

Geany - GTK based
http://www.geany.org/Main/AllFiletypes


There are many other general purpose editors that can edit Fortran including: Vi, Emacs, EditPlus.

String Manipulation
====================
There is a misconception that the string manipulating and handling capabilities are limited. However, it may not be as limited as initially thought. Here are a few useful string handling features from poplular languages that also exist in Fortran.

Comparing Substring:
   INDEX( string, substring) -> returns integer representing the first position of occurance of the substring in string.
   Converting Integer to String
write(charWord, '(I5)') ii-1
where ii is an integer which is written to the character variable 'charWord'.