Finally, we get to put together the new function (from subsection 3.2.2) and subroutine (from subsection 3.3.3) in the main program of the tsunami simulator. In a nutshell, this program has the same functionality and behavior as the previous version from chapter 2. The key difference is that now we’ve abstracted away the code to set the initial conditions and to calculate the finite difference of an array, as you can see in the following listing.
Listing 3.19 The updated complete code of the tsunami simulator
program tsunami
implicit none
integer :: n
integer, parameter :: grid_size = 100
integer, parameter :: num_time_steps = 100
real, parameter :: dt = 1, dx = 1, c = 1
real :: h(grid_size)
integer, parameter :: icenter = 25
real, parameter :: decay = 0.02
if (grid_size <= 0) stop 'grid_size must be > 0' ❶
if (dt <= 0) stop 'time step dt must be > 0' ❶
if (dx <= 0) stop 'grid spacing dx must be > 0' ❶
if (c <= 0) stop 'background flow speed c must be > 0' ❶
call set_gaussian(h, icenter, decay) ❷
print *, 0, h
time_loop: do n = 1, num_time_steps
h = h - c * diff(h) / dx * dt ❸
print *, n, h
end do time_loop
contains
pure function diff(x) result(dx) ❹
real, intent(in) :: x(:)
real :: dx(size(x))
integer :: im
im = size(x)
dx(1) = x(1) - x(im)
dx(2:im) = x(2:im) - x(1:im-1)
end function diff
pure subroutine set_gaussian(x, icenter, decay) ❺
real, intent(in out) :: x(:)
integer, intent(in) :: icenter
real, intent(in) :: decay
integer :: i
do concurrent(i = 1:size(x))
x(i) = exp(-decay * (i - icenter)**2)
end do
end subroutine set_gaussian
end program tsunami
❶ Checks input values and aborts if invalid
❷ Calls the subroutine to initialize water height
❸ Computes the finite difference of water height on the fly by calling the diff function
❹ Function to compute the finite difference of an input array
❺ Subroutine to initialize the input array to a Gaussian shape
At this point, our simulator produces exactly the same results as its previous version from chapter 2, and this is intended! The goal of this chapter was to refactor our code from a purely imperative to a more procedural style. If you check out the code from GitHub, you can test the correctness of the output by comparing the output from the two versions. The following listing shows what you should use to compare that output.
Listing 3.20 Comparing tsunami simulator results
git clone https://github.com/modern-fortran/tsunami ❶
cd tsunami
make ❷
src/ch02/tsunami > tsunami_v2.txt ❸
src/ch03/tsunami > tsunami_v3.txt ❹
diff tsunami_v2.txt tsunami_v3.txt ❺
❶ Gets the code from GitHub–do this only if you haven’t before.
❷ This builds the programs for each chapter; we’ll use only v2 and v3 here.
❸ Runs the v2 of the program and pipes the output into a file
❺ Finds differences between the two outputs–there should be no output here.
This listing shows all the steps to get the code, compile it, run the chapter 2 and 3 versions of the tsunami simulator, and store the outputs of each version in their own file. It then compares the files to make sure they’re exactly the same.