BEAT-II Fortran

The BEAT-II Fortran interface is a direct wrapping of all functions that are available in the BEAT-II C library.

Currently the BEAT-II Fortran interface is only supported on Unix based platforms (i.e. Linux, SUN, Mac OS X, etc.). Whether the interface also works on Windows is unkown.

This page describes how to use the wrapped interface and how to compile your own Fortran programs with BEAT.

Contents

Supported Fortran versions

The Fortran interface can be used with both Fortran 77 and Fortran 90. However, the Fortran interface is neither fully Fortran 77 nor fully Fortran 90 compliant. Fortran 77 requires that identifiers (i.e. variable and function names) are not longer than 6 characters and with Fortran 90 they should be no longer than 31 characters. Furthemore Fortran 77 does not allow '_' characters in identifiers. For both the BEAT interface, however, some identifiers are longer than 31 characters and they all contain '_' characters. Fortunately, most Fortran compilers shouldn't have any problems dealing with these exceptions.

Besides the identifier naming issue, the Fortran interface should be fully compliant with Fortran 77 (and, since Fortran 77 is a supported subset of Fortran 90, the interface is thus also compliant with Fortran 90).

Differences between C and Fortran

This section details the differences between the C and Fortran interfaces of BEAT and explains how the wrapping was done. Although most of the BEAT-II functions are mapped 1-to-1 from C to Fortran there are some guidelines and some exceptions that you should be aware of.

Type sizes

Both the C and the Fortran standards do not prescribe fixed byte sizes for their integer types. On most platforms for C an 8 bit integer is represented by a char, a 16 bit integer by a short, a 32 bit integer by int or long, and a 64 bit integer by a long long (although this last type has only been recently added to the C standard). Fortran (version 77 to be precise) on the other hand only supports the INTEGER type, which is 32 bits large on most systems. However, most Fortran 77 compilers support an extension that allows you to define e.g. a 16 bit / 2 byte integer by INTEGER*2. Fortran 90 on the other hand, doesn't support this INTEGER*... mechanism, but uses a system in which you can specify which kind of integer you want (e.g. INTEGER(4)). Unfortunately this system is not very portable (you need to use the intrinsic function SELECTED_INT_KIND to find the kind index for the precision you want) and is not guaranteed to give you a variable that has the exact number of bytes that you want.

Another issue is that C supports both signed and unsigned integer types, but in Fortran (both Fortran 77 and Fortran 90) all integers are signed (i.e. unsigned types are not supported).

For the C interface of BEAT the type size issue has been solved by introducing special types for 8/16/32/64 bit integers (both signed and unsigned): int8_t, uint8_t, in16_t, uint16_t, int32_t, uint32_t, int64_t, and uint64_t. But these types are only used for cases where portabillity was really needed, which, in case of BEAT, is for variables that contain data that was read from product files. For internal variables, such as e.g. result codes and indices, BEAT uses the native C type int.

Now what does all this mean for your Fortran program? The thing to remember is that when you pass arguments to a wrapped BEAT function from Fortran that you should pass variables that are the exact same size in bytes as what BEAT expects. Unsigned integers will be casted to signed integers, so if you try to retrieve e.g. an uint32 value mind that values >= 2.147.483.648 will appear in Fortran as negative values.

The list of function prototypes below gives an overview of how you should use the wrapped functions when you use a Fortran 77 compiler that supports the INTEGER*... extension.

For floating point data the situation is a bit more straightforward. BEAT requires that your system uses IEEE 754 for storing single and double precision floating point values. If this is the case then the C types float and double should be 100% equal to the Fortran types REAL and DOUBLE PRECISION.

Pointers

In the BEAT-II C interface several items, such as BEAT-II records, are passed as pointers. Since Fortran doesn't have a proper type to store such handles you should use a variable of type INTEGER to store these handles (this is also reflected in the function prototypes below).

Beware that using an INTEGER is only valid when you are on a 32-bit platform. If you are on a 64-bit platform where pointers are 64 bits large then you should use a 64 bit integer type (such as INTEGER*8) for pointer values.

Strings

There is a big difference in the way C and Fortran deal with string data. String data in C can be allocated dynamically and the exact length of a string is determined by a termination character (the character with ascii code 0: CHAR(0)). In Fortran all strings are fixed in size (the size is determined by the dimensions of the character array) and string data is padded on the right with space characters if the string is shorter than the size of the character array.

For the BEAT-II Fortran interface the translation between C strings and Fortran strings is done completely automatically for you. If you provide a character array of sufficient size, string data will be passed properly from Fortran to C and back again. If your character array is too short to fit the string data you requested from BEAT, then the BEAT-II Fortran interface will automatically truncate the string data such that it fits in your character array. There are a few cases in the function prototypes below where an explicit size is provided for the CHARACTER*(...) parameter (e.g. CHARACTER*(BEAT_UTC_STRING_LENGTH)). In these cases you should provide a character array with at least this size or the function will return an error.

Enumeration values and constants

For the BEAT-II C interface a lot of constant values, such as BEAT-II error codes, enums, etc. are named constants. For the Fortran interface a beatl2.inc is available that contains a full list of all available named constants (using the PARAMETER construct).

The beatl2.inc file also contains return type definitions for all wrapped functions.

Indices

Normally in Fortran all indices start with one. For instance, the first element of an array A is retrieved using A(1). In C all indices are zero based (i.e. the first element of A is A[0]. The BEAT-II Fortran interface provides no wrapping for these indices. This means that you will have to pass all index parameters to BEAT functions using zero based indices. For example, BEAT_CURSOR_GET_FIELD_TYPE(CURSOR,2,TYPE) will get the type of the third BEAT-II record field.

Functions that are only available in Fortran

The Fortran interface contains some additional functions to deal with global BEAT variables, BEAT-II record data, etc.

When wrapping a C interface to Fortran it is not possible to make global variables from the C interface available in Fortran. To solve this problem we have provided access routines to such variables in the BEAT Fortran interface. The functions BEATL2_VERSION and BEATL2_GET_ERRNO let you retrieve the values of the global C variables libbeatl2_version and beatl2_errno.

In C the data for a BEAT-II record field is retrieved using a generic pointer. Such pointers are not supported in Fortran (77). Furthermore, if a field contains string data then each string element needs to be converted from a C string to a Fortran string when you want to retrieve it (and vice versa if you want to set it). To be able to deal with field data from BEAT-II records, eight additional Fortran functions have been introduced: BEATL2_DATA_GET_UINT8, BEATL2_DATA_SET_UINT8, BEATL2_DATA_GET_INTEGERS, BEATL2_DATA_SET_INTEGERS, BEATL2_DATA_GET_DOUBLES, BEATL2_DATA_SET_DOUBLES, BEATL2_DATA_GET_STRINGS, BEATL2_DATA_SET_STRINGS (see below for the exact function definitions) (mind that for the UINT8 functions a hard cast from unsinged to signed (or vice versa) is performed!).
The first argument to these functions is the field data pointer that you can retrieve with BEATL2_RECORD_GET_FIELD_DATA. The last argument is your local Fortran variable for INTEGER*1, INTEGER, DOUBLE PRECISION, or CHARACTER data. This can be either a single element (if you want to read only one element) are a multi-dimensional array. With the second and third parameters you can provide an offset and number of elements. Using these two parameters it is possible to set/get only part of the field data (the offset/num_elements parameters refer to the field data block, not to your own Fortran variable). The offset is a one-dimensional index for the field data. For example, if your field data has dimensions [6,4] then you can read a maximum of 24 elements and the offset parameter can range from 0 to 23. When you set/get field data the funcion will always assume C array ordering (i.e. the last index is the fastest running).

Creating your Fortran program

After you have build and installed BEAT, you will have a directory '<prefix>/share/beat/fortran' (with <prefix> being the installation directory you provided to the BEAT configure script). In this directory you will find a Makefile, a checkf77.sh script, the beatl2.inc include file, and the wrapper file beatl2_fortran.c that should be linked into your BEAT-II Fortran program, and a series of example files.

When you ran the ./configure script of BEAT, the configure script was automatically locating your Fortran compiler and finding out which options it requires. These settings should already be included in the Makefile. You are however advised to check the contents of the Makefile in order to verify that these settings are correct. If you change the Fortran compiler to a different compiler then make sure to also run the checkf77.sh script (pass your Fortran compiler as parameter: e.g. ./checkf77.sh g77) to find out what options should be assigned to the WRAPFORTRAN_FLAGS variable.

Note: Although the F77 variable in the Makefile suggests that it is only meant for Fortran 77 compilers you can safely let it point to a Fortran 90/95 compiler.

After verifying the Makefile you can run:

$ make

This should build all examples. If this succeeds then just copy the files Makefile, beatl2.inc, and beatl2_fortran.c to a directory of your own and modify the Makefile such that it works with your own Fortran program.

The fortran interface comes with an example that should be extensive enough to get you started writing your own Fortran programs using BEAT.

Functions

Below you will find an overview of all available Fortran functions. For a full description of each function please refer to the description of the corresponding C function in the BEAT-II C interface documentation. There are a few functions that are Fortran only, but these are described in the previous paragraphs.

BEAT-II Functions


SUBROUTINE BEATL2_VERSION(CHARACTER*(*) VERSION)

INTEGER FUNCTION BEATL2_INIT()
SUBROUTINE       BEATL2_DONE()

INTEGER FUNCTION BEATL2_GET_ERRNO()
SUBROUTINE       BEATL2_ERRNO_TO_STRING(INTEGER ERR, CHARACTER*(*) STR)

INTEGER FUNCTION BEATL2_INGEST(INTEGER NUM_FILENAMES, CHARACTER FILENAMES(...)*(*), CHARACTER*(*) FILTER, INTEGER RECORD)

INTEGER FUNCTION BEATL2_RECORD_CREATE()
SUBROUTINE       BEATL2_RECORD_REMOVE(INTEGER RECORD)

INTEGER FUNCTION BEATL2_RECORD_GET_NUM_FIELDS(INTEGER RECORD)
INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_INDEX_FROM_NAME(INTEGER RECORD, CHARACTER*(*) FIELD_NAME)

INTEGER FUNCTION BEATl2_RECORD_ADD_FIELD(INTEGER RECORD, CHARACTER*(*) FIELD_NAME, INTEGER TYPE, INTEGER NUM_DIMS, INTEGER DIM(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_RECORD_ADD_STRING_FIELD(INTEGER RECORD, CHARACTER*(*) FIELD_NAME, CHARACTER*(*) STR)
INTEGER FUNCTION BEATL2_RECORD_REMOVE_FIELD(INTEGER RECORD, INTEGER INDEX)

INTEGER FUNCTION BEATL2_RECORD_ATTACH_FIELD(INTEGER RECORD, CHARACTER*(*) FIELD_NAME, INTEGER TYPE, INTEGER NUM_DIMS, INTEGER DIM(BEATL2_MAX_N_DIMS), INTEGER FIELD_DATA)
INTEGER FUNCTION BEATL2_RECORD_DETACH_FIELD(INTEGER RECORD, INTEGER INDEX, INTEGER FIELD_DATA)

INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_NAME(INTEGER RECORD, INTEGER INDEX, CHARACTER*(*) FIELD_NAME)
INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_TYPE(INTEGER RECORD, INTEGER INDEX, INTEGER TYPE)
INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_DIM(INTEGER RECORD, INTEGER INDEX, INTEGER NUM_DIMS, INTEGER DIM(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_NUM_ELEMENTS(INTEGER RECORD, INTEGER INDEX, INTEGER NUM_ELEMENTS)
INTEGER FUNCTION BEATL2_RECORD_GET_FIELD_DATA(INTEGER RECORD, INTEGER INDEX, INTEGER FIELD_DATA)

INTEGER FUNCTION BEATL2_RECORD_CHANGE_FIELD_NAME(INTEGER RECORD, INTEGER INDEX, CHARACTER*(*) FIELD_NAME)

INTEGER FUNCTION BEATL2_RECORD_APPEND_DATA_TO_FIELD(INTEGER RECORD, INTEGER INDEX, INTEGER NUM_DIMS, INTEGER DIM(BEATL2_MAX_N_DIMS), INTEGER DATA)
INTEGER FUNCTION BEATL2_RECORD_APPEND_FIELD_TO_FIELD_BY_INDEX(INTEGER RECORD_1, INTEGER INDEX_1, INTEGER RECORD_2, INTEGER INDEX_2)
INTEGER FUNCTION BEATL2_RECORD_APPEND_FIELD_TO_FIELD_BY_NAME(INTEGER RECORD_1, CHARACTER*(*) FIELD_NAME_1, INTEGER RECORD_2, CHARACTER*(*) FIELD_NAME_2)
INTEGER FUNCTION BEATL2_RECORD_RESHAPE_FIELD_DATA(INTEGER RECORD, INTEGER INDEX, INTEGER DIM_ID, INTEGER NUM_DIM_ELEMENTS, INTEGER DIM_ELEMENT_ID(BEATL2_MAX_N_DIMS))

INTEGER FUNCTION BEATL2_APPEND(INTEGER RECORD_1, INTEGER RECORD_2)
INTEGER FUNCTION BEATL2_FIND_COLOCATED_DATA(INTEGER RECORD_1, INTEGER RECORD_2, DOUBLE PRECISION TIME_DISTANCE, DOUBLE PRECISION RADIAL_DISTANCE, DOUBLE PRECISION ALTITUDE_DISTANCE)
INTEGER FUNCTION BEATL2_SLICE(INTEGER RECORD, CHARACTER*(*) DIMENSION, INTEGER NUM_IDS, INTEGER ID(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_SLICE_RANGE(INTEGER RECORD, CHARACTER*(*) DIMENSION, INTEGER FROM_ID, INTEGER TO_ID)

INTEGER FUNCTION BEATL2_EXPORT(CHARACTER*(*) FORMAT, CHARACTER*(*) FILENAME, INTEGER RECORD)
INTEGER FUNCTION BEATL2_IMPORT(CHARACTER*(*) FORMAT, CHARACTER*(*) FILENAME, INTEGER RECORD)

INTEGER FUNCTION BEATL2_C_ARRAY_TO_FORTRAN_ARRAY_INT32(INTEGER*4 C_ARRAY, INTEGER*4 FORTRAN_ARRAY, INTEGER NDIMS, INTEGER DIM(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_FORTRAN_ARRAY_TO_C_ARRAY_INT32(INTEGER*4 FORTRAN_ARRAY, INTEGER*4 C_ARRAY, INTEGER NDIMS, INTEGER DIM(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_C_ARRAY_TO_FORTRAN_ARRAY_DOUBLE(DOUBLE PRECISION C_ARRAY, DOUBLE PRECISION FORTRAN_ARRAY, INTEGER NDIMS, INT DIM(BEATL2_MAX_N_DIMS))
INTEGER FUNCTION BEATL2_FORTRAN_ARRAY_TO_C_ARRAY_DOUBLE(DOUBLE PRECISION FORTRAN_ARRAY, DOUBLE PRECISION C_ARRAY, INTEGER NDIMS, INTEGER DIM(BEATL2_MAX_N_DIMS))

SUBROUTINE BEATL2_DATA_GET_UINT8(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, INTEGER*1 INT_DATA)
SUBROUTINE BEATL2_DATA_SET_UINT8(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, INTEGER*1 INT_DATA)
SUBROUTINE BEATL2_DATA_GET_INTEGERS(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, INTEGER*4 INT_DATA)
SUBROUTINE BEATL2_DATA_SET_INTEGERS(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, INTEGER*4 INT_DATA)
SUBROUTINE BEATL2_DATA_GET_DOUBLES(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, DOUBLE PRECISION DOUBLE_DATA)
SUBROUTINE BEATL2_DATA_SET_DOUBLES(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, DOUBLE PRECISION DOUBLE_DATA)
SUBROUTINE BEATL2_DATA_GET_STRINGS(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, CHARACTER STR(...)*(*))
SUBROUTINE BEATL2_DATA_SET_STRINGS(INTEGER FIELD_DATA, INTEGER OFFSET, INTEGER NUM_ELEMENTS, CHARACTER STR(...)*(*))