To use finite difference functions directly with our new Field instances, we’ll make simple wrappers around those functions. First, we’ll import the functions and make them available in the mod_field module:
use mod_diff, only: diffx_real => diffx, & ❶
diffy_real => diffy ❶
❶ Renames on import so we can use the original names
We want to keep the original names diffx and diffy, so I’ve renamed them on import to avoid a name conflict. In the following listing, we define the function diffx that takes a Field instance as input and calls diffx_real under the hood to calculate the finite difference of the input field.
Listing 8.11 A wrapper function to pass a Field instance to diffx
pure function diffx(input_field)
class(Field), intent(in) :: input_field ❶
real(real32), allocatable :: diffx(:,:) ❷
diffx = diffx_real(input_field % data) ❸
end function diffx
❶ A Field instance as the input argument
❷ The result is a two-dimensional dynamic array.
❸ Passes the data component to the diff function that operates on real arrays
How about the diffy function? Its definition is the same as for diffx, except that it invokes diffy_real under the hood. I’m omitting its listing here for brevity.
Voilà! We can now import both the Field class and the diffx and diffy wrapper functions from mod_field, and use them just like we would plain ol’ Fortran arrays, as shown in the following listing.
Listing 8.12 Applying a finite difference function to a Field instance
use mod_field, only: Field, diffx, diffy ❶
type(Field) :: h, dh_dx, dh_dy ❷
h = Field('h', [100, 100]) ❸
dh_dx = diffx(h) ❹
dh_dy = diffy(h) ❹
❶ Imports type and functions from a module
❸ Initializes a Field instance with size 100 * 100
❹ Computes finite differences in x and y
In this snippet, I declared two instances of Field type, h and dh. I initialized h as a two-dimensional field of 100 by 100 data points, of which I then computed the finite differences using diffx and diffy and assigned them to dh_dx and dh_dy, respectively. This technique allows us to use the same solver code as we did with whole-array operations in the previous versions of the tsunami simulator. For example, when computing the value of water height at the next time step, we can write
h = h - (diffx(u * (hm + h)) / dx &
+ diffy(v * (hm + h)) / dy) * dt
In this snippet, all prognostic variables (that is, variables that we’re calculating the solution for) are Field instances–h, hm, u, and v.
Compatibility between Field instances and real arrays
You may have noticed that in listing 8.12, we assigned the result of diffx(h) (a two-dimensional real array) to dh, a Field instance. Normally this shouldn’t work, because the compiler on its own doesn’t know how to assign a real array to a Field instance. For this to work, we’ll need to define the custom assignment operator for the Field class with a special function. We’ll explore this and other advanced derived type topics in detail in chapter 10.