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.
|