File: InterfaceFortran2003.md

package info (click to toggle)
tasmanian 8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,852 kB
  • sloc: cpp: 34,523; python: 7,039; f90: 5,080; makefile: 224; sh: 64; ansic: 8
file content (138 lines) | stat: -rw-r--r-- 7,792 bytes parent folder | download
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Interface Fortran 2003

Tasmanian comes with Fortran 2003 interface generated by [Swig-Fortran](https://github.com/swig-fortran). The automatic generation makes the code easy to maintain and support, and the generation process is done off-line by the development team; hence, users are not required to install Swig and can use the interface with just a regular Fortran compiler. Furthermore, the 2003 standard support objects which allows for the OOP interface of Tasmanian C++ to be duplicated similar to Python and thus the on-line C++ Doxygen documentation is now relevant to Fortran as well.

The module is called `Tasmanian` and requires Fortran 2003 and a class `TasmanianSparseGrid` type is used. Currently, the Tasmanian Sparse Grid module has been implemented together with the MPI Addons; the Dream module and the remainder of the Addon templates are not supported (possibly in the future).

Simple example:
```
program tasmanian_demo
    use Tasmanian
    use, intrinsic :: iso_c_binding
    implicit none
    type(TasmanianSparseGrid) :: grid
    real(C_DOUBLE), dimension(:,:), allocatable :: points
    integer :: i, j

    grid = TasmanianSparseGrid()
    call grid%makeGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_clenshawcurtis)

    allocate(points(grid%getNumDimensions(), grid%getNumPoints()))
    call grid%getPoints(points(:, 1))

    do i = 1, grid%getNumDimensions()
        do j = 1, grid%getNumPoints()
            write(*,*) points(i, j)
        enddo
    enddo

    deallocate(points)
    call grid%release()
end program tasmanian_demo
```

Line by line:
* The `TasmanianSparseGrid` object must be initialized and deleted with the commands
```
grid = TasmanianSparseGrid()
call grid%release()
```
* The make-grid commands have the same syntax as C++ with the enumerate types replaced by integer constants with identical names and the `tsg_` prefix.
* The double-precision type used in all calls is `real(C_DOUBLE)` but it could easily be the Fortran native `DOUBLE PRECISION` so long as the type is compatible with `C_DOUBLE`.
* The organization of the points is in two dimensional matrix, where each column corresponds to the coordinates of a single point; however, the API accepts only single dimensional arrays (c-style), hence the conversion
```
call grid%getPoints(points(:, 1))
```

### See the Included Examples
Several Fortran examples are provided that duplicate the functionality in C++ and Python, which makes it easy to compare and contrast.

### Filenames and Strings
Strings works differently between the Fortran, C and C++ languages. Tasmanian I/O methods accept C-style of null-terminated character arrays, but Fortran character arrays are often padded with white spaces. The Fortran `trim()` command can be used to remove trailing white spaces from the filenames and avoid confusion with C++. See the following example that assumes a file with the name "123" is holding a valid Tasmanian sparse grid and we want to read the grid into a Tasmanian object:
```
    character(len = 3), parameter :: filename = "123"
    character(len = 4), parameter :: padded = "123"

    grid = TasmanianSparseGrid()
    grid%read(filename)     ! OK, reads from "123"
    ! grid%read(padded)     ! Bad, tries to read from "123 "
    grid%read(trim(padded)) ! OK, removes the extra space
```

### Row-vs-Column Format
C and C++-14 standards do not have a native two dimensional data-structure and many of the inputs and outputs for Tasmanain are logically organized in strips of data with a fixed stride. When interfacing with a language that supports two dimensional data (e.g., matrix type) it is beneficial to make the translation, but without a copy or manual transposing of the data to avoid performance degradation. Therefore, the strips of data are aligned to the dimension of the fastest index, e.g., the rows for a row-major language (Python-numpy) and columns for a column-major one (Fortran). The Matlab interface uses row-major format due to the ascii file standard used in the background.

The five point Clenshaw-Curtis grid has 5 points, `(0,0)`, `(0,-1)`, `(0,1)`, `(-1,0)` and `(1,0)`. The matrix generated by Fortran will have the organization:
```
0  0 0 -1 1
0 -1 1  0 0
```
while the Python and Matlab equivalents would be:
```
 0  0
 0 -1
 0  1
-1  0
 1  0
```

### Factory and Helper Methods and Namespaces

Fortran 2003 does not support namespaces and the wrapper API works directly with user allocated matrices. The `make***Grid()` factory methods have been replaced with:
```
    TasGrid::makeGlobalGrid          => TasmanianGlobalGrid
    TasGrid::makeSequenceGrid        => TasmanianSequenceGrid
    TasGrid::makeLocalPolynomialGrid => TasmanianLocalPolynomialGrid
    TasGrid::makeFourierGrid         => TasmanianFourierGrid
    TasGrid::makeWaveletGrid         => TasmanianWaveletGrid
    TasGrid::readGrid                => TasmanianReadGrid
    TasGrid::copyGrid                => TasmanianCopyGrid
```
Although the methods do not support array API and hence anisotropic weights and level limits still require the use of the member functions, e.g., `makeGlobalGrid()`.

The static array API works with allocatable variables but requires user allocation of memory and is not very expressive. Functions that return pointers to pre-allocated data are preferable; however, functions and subroutines cannot share names in generic overloads. Thus, the Fortran functions use alternative names that start with `return` as opposed to `get`, e.g.,
```
    real(C_DOUBLE), dimension(:,:), pointer :: points
    ...
    points => grid%returnPoints()
    ...
    deallocate(points)
```
The helper function are:
```
    points => grid%returnLoadedPoints()
    points => grid%returnNeededPoints()
    points => grid%returnPoints()
    weight => grid%returnQuadratureWeights()
    coeffs => grid%returnHierarchicalCoefficients()
    coeffs => grid%returnComplexHierarchicalCoefficients()
```
See the next section for complex numbers.

### Complex numbers

Tasmanian Fourier grids utilize complex numbers in the background which is usually opaque to the user. However, the methods to set and get hierarchical coefficients do use complex numbers, see the C++ API for details. The C++ API returns raw pointers which cannot be manipulated directly from within Fortran; hence the C++ methods are replaced with methods that accept and return copies of the data and utilize the complex format (similar to Python and MATLAB). The two methods are:
```
    complex(C_DOUBLE), dimension(:, :), pointer :: coeffs, new_coeffs
    ...
    coeffs => grid%returnComplexHierarchicalCoefficients()
    grid%setComplexHierarchicalCoefficients(new_coeffs)
```

### MPI Fortran Capabilities

If Tasmanian has been compiled with MPI support, a second Tasmanian module will be included that contains Fortran wrappers for the MPI C++ templates. The module is called `Tasmanian_mpi` and must be used in conjunction with `Tasmanian`, e.g.,
```
    use Tasmanian
    use Tasmanian_mpi
    use mpi
```
The `Tasmanian_mpi` module instantiates the templates as Fortran functions and pre-pends `tsg` to the names to avoid possible namespace conflicts, e.g.,
```
    ierr = tsgMPIGridSend(grid, destination, tag, comm)
    ierr = tsgMPIGridRecv(grid, source, tag, comm)
    ierr = tsgMPIGridBcast(grid, root, comm)
    ierr = tsgMPIGridScatterOutputs(grid, subgrid, root, tag, comm)
```
Note, each methods returns the MPI error code returned by C++ which is different from the way MPI usually works under Fortran, but that is due to the way Swig instantiates the templates and the fact that the error comes from MPI call in the C++ section of the code. The templates always work in binary communication mode, since the ASCII mode is mostly for debugging purposes on the C++ side.