[CCP14 Home: (Frames | No Frames)]
CCP14 Mirrors: [UK] | [CA] | [US] | [AU]

(This Webpage Page in No Frames Mode)

CCP14

Methods, Problems and Solutions

Scientific Fortran Links and Creating GNU G77 Fortran Compiler compatible Dynamic Arrays (Automatic Arrays/Dynamic Memory Allocation)

The CCP14 Homepage is at http://www.ccp14.ac.uk

[Back to Problems and Solutions]

[Installing and Setting up Free Compilers and Software Creation Toolkits] | [Installing and Setting up EGCS-MING 32 C/C++/GCC/G++ and Fortran 77 (F77/G77) for Win32 from Mumit Khan's Web/FTP site] | [Installing a Linux and Win95 Dual Boot System (including GNU G77 fortran compilers)] | [Installing EGCS G77 Fortran 77 on FreeBSD 3.3] | [Alternative Opinions on which Linux and Fortran compiler and multi booting system to use for Crystallography] | [Resources and Recommendations for Developers] |

[Acknowledgements] | [Background and Warning] | [Manually Increasing arrays and Ulimit Problems on UNIX Machines]
[Examples of F90 style Dynamic Arrays/Automatic Arrays in Fortran that will compile on GNU F77/G77]
[Scott Belmonte example code and information] | [Dave Love example code and information] | [Free Fortran Compilers and Fortran Relevant Links] | [Links to Interfacing Fortran and C]

Extra Additions/Opinions/Corrections are very Welcome

Acknowledgements

Kudos to Scott Belmonte and Dave Love for providing the examples and information on this. Some mistakes and false interpretations may have occurred in the translation of this information. Thus all blame for errors or dodgy observations should be passed to the author of this page, CCP14 Secretary, Lachlan Cranswick (E-mail: l.cranswick@dl.ac.uk).


Background and Warning

The strict Fortran 77 specification does not allow Automatic Arrays (Dynamic Arrays/Dynamic Memory Allocation). However, the freely available GNU Fortran 77 compiler (G77) does allow you to use the Fortran 90 Automatic Array methods with a very good chance that it will compile happily and run when compiled with G77. Other commercial Fortran 90 compilers should not have a problem with being able to use Automatic Arrays as this is allowed under the Fortran 90 specification.

However, 100% strict Fortran 77 compilers will not be able to compile code that uses dynamic memory allocation. GNU G77 can handle Automatic Arrays due to it having some Fortran 90 extensions. An example of this are giving below.

Other options could to use a combination of Fortran and C code for managing Automatic Arrays. An example of this is given below. Be wary that this could be a very compiler and OS specific method and tweaks may be required when porting to a different system.

Refer to: Array processing (part of the Resources for Learning Fortran 90)


Also refer to Alternative Opinions on which Linux and Fortran compiler and multi booting system to use for Crystallography

And refer below to:

and

  • g95 Project
    • "The goal of the g95 project is to create a free, open source Fortran 95 compiler. The code has been donated to the Free Software Foundation for inclusion in GCC, the Gnu Compiler Collection."
    • Original at http://g95.sourceforge.net/

Manually Increasing arrays and Ulimit Problems on UNIX Machines

One method for getting around small static array sizes in Fortran programs is just to increase the relevant array sizes and re-compile. However, you may find that programs do not run or fail midstream with cryptic or zero indication why this is occuring. If unfamiliar with this property of UNIX, it may take quite some time to realise what is going on. An example of this type of behaviour follows.

./maps: /sbin/loader: Fatal Error: cannot map Main

The problem here is the program is exceeding the amount of memory an individual program is allowed to request under a UNIX shell. The default allowed amount of memory can vary depending on the shell and the version of UNIX.

A quick fix could be to change to a different shell (such as bash). A possible better idea would be to do man ulimit and find out what options your operating system allows for this.


Examples of F90 style Dynamic Arrays/Automatic Arrays in Fortran that will compile on GNU F77/G77

Example from Scott Belmonte

Date: Tue, 23 May 2000 10:48:55 +0100 (BST) 
From: "Scott A. Belmonte" 
To: "L. Cranswick" [L.M.D.Cranswick@dl.ac.uk] 
Subject: Re: What does it mean when a Fortran program does this? 


On Mon, 22 May 2000, L. Cranswick wrote:

> 
> Hi Scott,
> 
> have been increasing the arrays of a fortran
> program to get it to handle a larger problem on
> a Digital Alpha machine - but it gives an error like:
> 
> 22879:maps: /sbin/loader: Fatal Error: cannot map Main
> pxsv6% ./maps              
> 18152:./maps: /sbin/loader: Fatal Error: cannot map Main
> 
> 
> What does this means - arrays going over each-other or
> something like this?
> 


I've not come across this exact problem before, and I would need to see
the code and the actual compilation instructions, but judging by what you
are doing to the code, it sounds like the arrays you are defining are to
big to be allocated on the stack. You can do two things to get round
this:


1) The stack usage is normally limited by the shell. Type ulimit -a to see
the restrictions. If you are running csh/tcsh then there is not much you
can do about is because for some reason it does not let you increase the
limit. You could try running bash, it lets you change the limits. Change
the stack limit using ulimit -s #, where # is the number of 512-byte
blocks to set the limit to, or ulimit -s unlimited to grab as much as
you're allowed. If this does not work then go to 2.


2) Dynamically allocate the memory at run time. This actually is always
the best thing to do when data arrays start to become very big and has the
advantage that you don't need to know the size of the array before you run
the program. There is no standard way to dynamically allocate objects in
f77. You will have to use the libc malloc() function. You can do dynamic
allocation in Fortran 90. I'm not very hot in Fortran 90 (I'm a C
man myself) but something like this should work:


      PROGRAM alloc_example
C  Allocate a 1-d real array with N elements
      INTEGER N, ALLOC_ERR
      REAL, ALLOCATABLE :: DATA(:)


C  You would calculate N at run time or see it to the valus you want.
      N = 10 


C  ALLOC_ERR is set to a positive integer (i.e. not zero) if an error
C  occur with the allocation, such as out-of-memory.
      ALLOCATE (DATA(N), STAT = ALLOC_ERR)


      IF (ALLOC_ERR.NE.0) THEN 
        WRITE(*,*) 'ERROR: Could not alloc memory'
        STOP
      END IF


C Zero array, or do what ever you want to do with it.
      DO I = 1,N
        DATA(I) = 0.0
      END DO


C Once you finished, deallocate the memory.
      DEALLOCATE(DATA)


      END


Digital Alpha has a Fortran 90 compiler (f90) but it might be a nightmare
trying to compile old f77 code with it.


There is another possiblity that the linker, for some reason, cannot find
the main block. This is entirely due to the compilation. But seeing
that it has compiled and worked before (I assume) then this is unlikely to
be the problem.


I hope this helps. I can help you with incorporating malloc into the code
but linking with c routines is quite non-portable so once you have changed
the code to work with Alpha compilers you may ahve to customise for any
other machine that you want to compile on.


Scott.


---------------------------------------------------------------------
Dr Scott A. Belmonte        
University of Edinburgh            
Room C18A                          
Daresbury Laboratory, Daresbury
Warrington
WA4 4AD
---------------------------------------------------------------------


Example from Dave Love

Date: Thu, 25 May 2000 16:42:49 +0100 
To: l.cranswick@dl.ac.uk 
Subject: dynamic allocation 
From: Dave Love 
User-Agent: Gnus/5.0807 (Gnus v5.8.7) Emacs/21.0.90 


Here's a trivial example of f90 automatic arrays.


$ cat alloc.f
      subroutine allocs (n)
      real vector (n)
      do i=1,n
        vector (i) = i
      end do
      print *, vector
      end


      print *, 'Array dimension?'
      read *, n
      call allocs (n)
      end
$ g77 alloc.f && ./a.out
 Array dimension?
10
  1.  2.  3.  4.  5.  6.  7.  8.  9.  10.
$ 

-----------------------


Here's the C part of the support I wrote for CCP4:


/* \section{Dynamic memory allocation}                                      */
/* It's nice to be able to determine array sizes at run time to avoid       */
/* messy recompilation.  The only way effectively to get dynamic            */
/* allocation in Fortran77 reasonably portably is to do the allocation,     */
/* e.g.\ in C, and invoke the Fortran routine passed as a parameter with    */
/* pointers to the allocated memory which it will treat as arrays.  If we   */
/* want to allow more than one array, it's more tricky.                     */
/*                                                                          */
/* \subsection{{\tt subroutine ccpal1 (\meta{routne}, \meta{n}.             */
/*     \meta{type}, \meta{length})}}                                        */
/* Arranges to call subroutine \meta{routne} with \meta{n} array            */
/* arguments.  Each has a type indicated by \meta{type}$(i)$ and a length   */
/* given by \meta{length}($i$).  \meta{type} is an integer array with       */
/* values 1, 2, 3, 4 inidcating {\tt                                        */
/*   INTEGER}, {\tt REAL}, {\tt DOUBLE PRECISION} and {\tt COMPLEX}         */
/* respectively.                                                            */
/* It's not immediately clear what all the Fortran/C                        */
/* conventions are for passing [[CHARACTER]] arrays, so we'll arrange a     */
/* higher-level interface and have [[types]] here just numeric.  The        */
/* Fortran ([[CCPALC]]) will also do argument validation.  Also the rules   */
/* for passing external routines as arguments aren't clear---assume         */
/* the obvious way.                                                         */
/*                                                                          */
/* There's a \idx{VMS} Fortran version of this, although the code here      */
/* does work fine in VMS\@.                                                 */
/*                                                                          */
/* NB: there's a possibility of a hook here to use memory-mapped files on   */
/* systems with the capability and insufficient VM\@.                       */
/*                                                                          */
/* Under protest, this now allocates zeroed storage for where programs      */
/* make bad assumptions.                                                    */
/*                                                                          */
/* <miscellaneous routines>=                                                */
#ifndef VMS                     /* we'll use the Fortran version in VMS*/
#ifndef _MVS
#if CALL_LIKE_HPUX
  void ccpal1 (routne, n, type, length)
  void (* routne) ();
  int *n, type[], length[];
#endif
#if defined (VMS) || CALL_LIKE_STARDENT
  void CCPAL1 (void (* routne) (), int *n, int type[], int length[])
#endif
#if CALL_LIKE_SUN
  void ccpal1_ (void (* routne) (), int *n, int type[], int length[])
#endif
#if CALL_LIKE_MVS
  void __stdcall CCPAL1 (void (* routne) (), int *n, int type[], int length[])
#endif
{
  int i, size, *leng[13];
  void *pointer[13];


  for (i=0; i<*n; i++) {
    switch (type[i]) {
    case 1:
      size = item_sizes[6]; break; /* integer */
    case 2:
      size = item_sizes[2]; break; /* real */
    case 3:
      size = 2*item_sizes[2]; break; /* double */
    case 4:
      size = 2*item_sizes[2]; break; /* complex */
    case 5:
      size = item_sizes[1]; break; /* bytes (logical or integer *1) */
    }
    pointer[i+1] = calloc ((size_t) length[i], (size_t) size);
    if (pointer[i+1] == NULL) fatal ("CCPALC: can't allocate memory");
    leng[i+1] = &(length[i]);   /* convenience */
  }
  switch (*n) {
  case 1:
    (* routne) (leng[1], pointer[1]);
    break;
  case 2:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2]);
    break;
  case 3:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3]);
    break;
  case 4:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4]);
    break;
  case 5:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5]);
    break;
  case 6:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6]);
    break;
  case 7:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7]);
    break;
  case 8:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7], leng[8], pointer[8]);
    break;
  case 9:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7], leng[8], pointer[8],
                leng[9], pointer[9]);
    break;
  case 10:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7], leng[8], pointer[8],
                leng[9], pointer[9], leng[10], pointer[10]);
    break;
  case 11:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7], leng[8], pointer[8],
                leng[9], pointer[9], leng[10], pointer[10],
                leng[11], pointer[11]);
    break;
  case 12:
    (* routne) (leng[1], pointer[1], leng[2], pointer[2],
                leng[3], pointer[3], leng[4], pointer[4],
                leng[5], pointer[5], leng[6], pointer[6],
                leng[7], pointer[7], leng[8], pointer[8],
                leng[9], pointer[9], leng[10], pointer[10],
                leng[11], pointer[11], leng[12], pointer[12]);
    break;
  }
  for (i=0; i<*n; i++)
    free (pointer[i+1]);
}


-----------------------


And the Fortran:


      SUBROUTINE CCPALC(ROUTNE, N, TYPE, LENGTH)
C     ==========================================
C
C     Arrange to call subroutine ROUTNE with N array arguments each of
C     length LENGTH (i) and type indicated by TYPE (i): 'i' == integer,
C     'r' == real, 'd' == double precision, 'c' == complex, 'b' ==
C     "byte" (logical*1 or integer*1, unportable and deprecated) .  TYPE
C     elements may have either case.
C     Consider `call ccpalc (fred, 3, types, lens)' with types = (/'i',
C     'r', 'c'/)  and lens = (/1000, 2000, 3000/).  This effectively does
C        call fred (1000, arr1, 2000, arr2, 3000, arr3)
C     with
C        subroutine fred (n1, foo, n2, bar, n3, baz)
C        integer n1, n2, n3, foo (n1)
C        real bar (n2)
C        complex baz (n3)
C        ...
C     Obviously all communication with ROUTNE must be by COMMON (or,
C     possibly, extra ENTRYs).  The allocated memory is freed on return
C     from ROUTNE.  As a concession, it's initially filled with zeroed
C     bytes.


C
C Arguments:
C ==========
C
C      ROUTNE (I)   EXTERNAL: routine to call
C           N (I)   INTEGER: number of arguments to ROUTNE (<=12)
C        TYPE (I)   CHARACTER*1 (*): type of arguments to ROUTNE:
C                      'I': INTEGER; 'R': REAL; 'D': DOUBLE PRECISION;
C                      'C': COMPLEX; 'B': LOGICAL*1 or INTEGER*1
C      LENGTH (I)   INTEGER*(*): number of elements in each (array)
C                       argument of ROUTNE
C_END_CCPALC
C
C     .. Scalar Arguments ..
      INTEGER N
C     ..
C     .. Array Arguments ..
      CHARACTER TYPE (*)
      INTEGER LENGTH (*)
C     ..
      EXTERNAL ROUTNE, CCPAL1, CCPUPC
      INTEGER I, ITYPE (12)
      CHARACTER TTYPE (12)
C     ..
      IF (N.LT.1 .OR. N.GT.12)
     +     CALL CCPERR (1, 'CCPALC: bad number of arguments')
      DO 10 I=1,N
        TTYPE (I) = TYPE (I)
        CALL CCPUPC (TTYPE (I))
        ITYPE (I) = INDEX ('IRDCB', TTYPE (I))
        IF (ITYPE (I) .EQ. 0) CALL CCPERR (1, 'CCPALC: bad TYPE: '//
     +       TYPE (I))
        IF (LENGTH (I).LE.0) CALL CCPERR (1, 'CCPALC: length <=0')
 10   CONTINUE
      CALL CCPAL1 (ROUTNE, N, ITYPE, LENGTH)
      END
C 
C
C_BEGIN_CCPALE
      SUBROUTINE CCPALE(ROUTNE, N, TYPE, LENGTH, LENDEF, PRINT)
C     =================================================
C
C     Arrange to call subroutine ROUTNE with N array arguments each of
C     length LENGTH (i) and type indicated by TYPE (i): 'i' == integer,
C     'r' == real, 'd' == double precision, 'c' == complex, 'b' == byte.
C     TYPE elements may have either case.  LENGTH points to an array of
C     environment variable (logical) names from which integer values are
C     read.  The lengths default to values from LENDEF.
C     This is a convenient interface to CCPALC to allow configuring of
C     the memory requirements on the command line where appropriate.
C     This may be useful if the memory requirements can't be determined
C     initially and it's necessary to guess.
C
C Arguments:
C ==========
C
C      ROUTNE (I)   EXTERNAL: routine to call
C           N (I)   INTEGER: number of arguments to ROUTNE (<=12)
C        TYPE (I)   CHARACTER*1 (*): type of arguments to ROUTNE:
C                      'I': INTEGER; 'R': REAL; 'D': DOUBLE PRECISION;
C                      'C': COMPLEX; 'B': LOGICAL*1 or INTEGER*1
C     LENGTH (I)   CHARACTER *(*): logical names representing the number
C                       of elements in each (array) argument of ROUTNE
C     LENDEF (I)   INTEGER (*): default lengths for the argument arrays
C     used if the appropriate LENGTH argument doesn't represent a
C     defined logical
C     PRINT  (I)   LOGICAL: whether or not to print the values of the
C     array lengths
C_END_CCPALE
C
C     .. Scalar Arguments ..
      INTEGER N
      LOGICAL PRINT
C     ..
C     .. Array Arguments ..
      CHARACTER TYPE (*),  LENGTH (*)*(*)
      INTEGER LENDEF (*)
C     ..
      EXTERNAL ROUTNE, CCPE2I, CCPALC, LUNSTO
      INTEGER I, LENG (12), CCPE2I, LUNSTO
C     ..
      DO 10 I=1,N
        LENG (I) = CCPE2I (LENGTH (I), LENDEF (I))
 10   CONTINUE
      IF (PRINT) THEN
        WRITE (LUNSTO(1), 
     +     '(/'' Memory allocation (logical name, type, elements):'')')
        WRITE (LUNSTO(1), '(3X, A, 1X, A, 3X, I10)')
     +       (LENGTH (I), TYPE (I), LENG (I), I=1,N)
      ENDIF
      CALL CCPALC (ROUTNE, N, TYPE, LENG)
      END


Free Fortran Compilers and Fortran Relevant Links

  • F2KCLI
    • WebSITE
    • F2KCLI is a free implementation of the proposed Fortran 200x (F2K) command line interface, which consists of three routines: COMMAND_ARGUMENT_COUNT : Returns the number of command arguments. GET_COMMAND_ARGUMENT : Returns a command argument. GET_COMMAND : Returns the entire command by which the program was invoked. F2KCLI provides versions of these routines for a very wide range of Fortran 77/9x compilers. Nearly 80 different platform/compiler combinations are supported. See the compatibility page for a full list.
    • Original at http://www.winteracter.com/f2kcli/



  • MathTools
    • WebSITE
    • A technical computing portal for scientific and engineering needs. The portal is free and contains over 20,000 links to technical computing programmers, covering Fortran, Excel, Java, MATLAB and others.
    • Original at http://www.mathtools.net



PGPLOT Graphics Subroutine Library - Tim Pearson
  • Contact: tjp@astro.caltech.edu
  • WEB SITE
  • "The PGPLOT Graphics Subroutine Library is a Fortran- or C-callable, device-independent graphics package for making simple scientific graphs. It is intended for making graphical images of publication quality with minimum effort on the part of the user. For most applications, the program can be device-independent, and the output can be directed to the appropriate device at run time."
  • Original at http://astro.caltech.edu/~tjp/pgplot/

DISLIN Scientific Data Plotting Software - Helmut Michels
  • Contact: michels@linmpi.mpg.de
  • WEB SITE
  • "DISLIN is intended to be a powerful and easy to use software package for scientists and programmers. DISLIN is free for the operating systems Linux and FreeBSD and for the MS-DOS and Windows 95/98/NT compilers GCC, G77 and LCC. The DISLIN plotting extensions for Java, Python and Perl and the DISLIN interpreter DISGCL can be used freely on all operating systems."
  • Original at http://www.linmpi.mpg.de/dislin/

Numerical Recipes in Fortran (and a book on Fortran 90) - the Art of Scientific Computing

Alternatives to Numerical Recipes.

Resources for Learning Fortran 90/Fortran-90 Resources

Fortran Market

ftnchek - GPL static Fortran 77 analyzer
  • "ftnchek is a static analyzer for Fortran 77 programs. It is designed to detect certain errors in a Fortran program that a compiler usually does not. ftnchek is not primarily intended to detect syntax errors. Its purpose is to assist the user in finding semantic errors. Semantic errors are legal in the Fortran language but are wasteful or may cause incorrect operation. For example, variables which are never used may indicate some omission in the program; uninitialized variables contain garbage which may cause incorrect results to be calculated; and variables which are not declared may not have the intended type. ftnchek is intended to assist users in the debugging of their Fortran program. It is not intended to catch all syntax errors. This is the function of the compiler. Prior to using ftnchek, the user should verify that the program compiles correctly."

  • Original at http://www.dsm.fordham.edu/~ftnchek/

Numerical methods for Fortran programmers


Links to Interfacing Fortran and C

C-Fortran Interface

Mixing Fortran and C

Calling C from Fortran

Interfacing Fortran and C

CFORTRAN: Interfacing C and FORTRAN


[Acknowledgements] | [Background and Warning] | [Manually Increasing arrays and Ulimit Problems on UNIX Machines]
[Examples of F90 style Dynamic Arrays/Automatic Arrays in Fortran that will compile on GNU F77/G77]
[Scott Belmonte example code and information] | [Dave Love example code and information] | [Free Fortran Compilers and Fortran Relevant Links] | [Links to Interfacing Fortran and C]

[Installing and Setting up Free Compilers and Software Creation Toolkits] | [Installing and Setting up EGCS-MING 32 C/C++/GCC/G++ and Fortran 77 (F77/G77) for Win32 from Mumit Khan's Web/FTP site] | [Installing a Linux and Win95 Dual Boot System (including GNU G77 fortran compilers)] | [Installing EGCS G77 Fortran 77 on FreeBSD 3.3] | [Alternative Opinions on which Linux and Fortran compiler and multi booting system to use for Crystallography] | [Resources and Recommendations for Developers] |

[Back to Problems and Solutions]

[CCP14 Home: (Frames | No Frames)]
CCP14 Mirrors: [UK] | [CA] | [US] | [AU]

(This Webpage Page in No Frames Mode)

If you have any queries or comments, please feel free to contact the CCP14