1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
%
% PSI Programmer's Manual
%
% PSI Fortran Code Section
%
% Daniel Crawford, 31 January, 1996
%
Most of the code in \PSItwo\ was in the Fortran 77 programming
language. Essentially all of the new development in \PSIthree\ has
been in C or C++. Since a small amount of Fortran code remains, in
this section we discuss the structure of PSI Fortran modules.
All Fortran 77 programs use static allocation for memory management.
This means that the memory requirements of the program must be
established when the program is compiled. While this allows Fortran
programs to avoid complicated and time-consuming memory manipulation
calls, it also may significantly reduce the applicability of the
program to computations of widely varying size. That is, if a
calculation requires a large amount of memory, the program may have to
be re-compiled before the calculation can be run; or, if only a small
amount of memory if required, but the program has been compiled to
allocate huge amounts of static memory, most of the memory will be
wasted.
PSI avoids this problem to a certain extent by first allocating the
memory using C function calls, and then passing a pointer to this
memory to the Fortran program. This means that the routine called
``\celem{main}'' (which must exist in every program, regardless of
programming language) is provided by a C program, and that the Fortran
code is treadted as a subroutine called immediately after the C
routine has finished the memory allocation. The Fortran subroutine is
always called \felem{fentry()}, and it requires a pointer to the
beginning of the available memory and the size of the memory in double
precision floating point words as arguments. This procedure also
allows the user to specify the amount of available memory in input.
The \library{alloc.a} library provides the code necessary for this
technique.
The Fortran modules also require an input parsing library separate
from that of the C modules, since the C/Fortran interface is not
standardized. This library, \library{libparse.a}, has numerous
similarities with its C counterpart, \library{libipv1.a} (see section
\ref{C_IP}), and its syntax is relatively intuitive. Finally, I/O in
the Fortran modules is handled very similarly to the old-style I/O in
the C modules. In fact, only the most high-level calls, such as
\felem{wreadw()} and \felem{rfile()} are actually written in Fortran.
The low-level routines are C functions which are constructed very
similarly to those in \library{libciomr.a}. All of the I/O routines
required by the Fortran modules may be found in \library{
io.a}.\footnote{The I/O routines to be found \library{iomr.a} are
obsolete and should never be used. I (TDC) look forward to the day
when this library is removed.}
\subsection{The Psi Preprocessor}\label{psipp}
Many of the existing Fortran codes in the \PSIthree\ package make
calls to the Fortran input parsing routines in \library{libparse.a}.
These routines return to the caller special error codes which tell the
program what problems (if any) were encountered in searching the input
for a special keyword or piece of data. Therefore, all the Fortran
codes need to know how to interpret these codes. In C, one would
normally simply \celem{\#include} a header file containing the code
definitions. However, the \felem{include} statement is not part of
the Fortran 77 standard. So, to get around this, and still maintain
portable code, the PSI preprocessor, \module{psipp} exists.
All Fortran codes in \PSIthree\ are stored in \file{.F} files, rather than the
usual \file{.f}. Each \file{.F} file is examined by \module{psipp} for lines
such as
\begin{verbatim}
#include <error.h>
\end{verbatim}
Such lines are interpreted by the preprocessor, and the correct header
file (in this case, \file{error.h}) is included (literally inserted)
into the new file, with the \file{.f} suffix. \module{psipp} can
understand a number of directives, including \felem{\#if},
\felem{\#ifdef}, \felem{\#elif}, \felem{\#else}, \felem{\#endif},
\felem{\#define}, and \felem{\#undef}.
\subsection{Debugging \PSIthree\ Fortran Code}
\PSIthree\ Fortran modules can be substantially more difficult than
their C counterparts to debug. (See section \ref{Debugging} for more
information.) This is because the Fortran source code (\file{.F}
suffix) must be preprocessed by \module{psipp} before it is passed to
the compiler (see section \ref{psipp}). Additionally, the
preprocessed files (\file{.f} suffix) are usually automatically
deleted when the compilation stops due to the \file{make} program's
defaults (all such intermediate files are deleted). So, if the
programmer tries to use the unprocessed code with the debugger, line
numbers won't match and the debugger's output will be meaningless. To
keep the preprocessed source files, \file{make} must be told that they
are important; add the following line to the \file{Makefile} in the
Fortran module's object code directory:
\begin{verbatim}
.PRECIOUS: %.f
\end{verbatim}
This is a GNU \file{make} directive which prevents deletion of all
intermediate \file{.f} files when the compilation stops. Then add the
current directory to the debugger's source directory search path, and
plow ahead. Note, however, that any changes made to \file{.f} files
must be duplicated in the corresponding unprocessed source \file{.F}
files to be permanent.
|