Tsunami Simulator with Modules#
Adapted from: “Modern Fortran: Building Efficient Parallel Applications” by Milan Curcic (Manning)
Program to Calculate the Temperature due to a Cold Front Using a Loop#
In this section the Tsunami Simulator is rewritten using Fortran Modules.
The file mod_inital.f08 contains:#
module mod_initial
private
public :: set_gaussian
contains
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 module mod_initial
The file mod_diff.f08 contains:#
! %module magic necessary so that jupyter fortran kernel knows that
! the code below is to be compiled as a module and not executable code.
!%module: mod_diff
module mod_diff
use iso_fortran_env, only: int32, real32
implicit none
private
public :: diff_upwind, diff_centered
contains
pure function diff_upwind(x) result(dx)
real(real32), intent(in) :: x(:)
real(real32) :: dx(size(x))
integer(int32) :: im
im = size(x)
dx(1) = x(1) - x(im)
dx(2:im) = x(2:im) - x(1:im - 1)
end function diff_upwind
pure function diff_centered(x) result(dx)
real(real32), intent(in) :: x(:)
real(real32) :: dx(size(x))
integer(int32) :: im
im = size(x)
dx(1) = x(2) - x(im)
dx(im) = x(1) - x(im - 1)
dx(2:im-1) = x(3:im) - x(1:im-2)
end function diff_centered
end module mod_diff
Main Program#
program tsunami
use iso_fortran_env, only : int32, real32
use mod_diff, only : diff => diff_centered
use mod_initial, only : set_gaussian
implicit none
integer(int32) :: n
integer(int32), parameter :: grid_size = 100
integer(int32), parameter :: num_time_steps = 5000
real(real32), parameter :: dt = 0.02, dx = 1, g = 9.8
real(real32), parameter :: hmean = 10
real(real32) :: h(grid_size), u(grid_size)
integer(int32), parameter :: icenter = 25
real(real32), parameter :: decay = 0.02
logical :: file_exists
open(9, file = 'tsunami_simulator_with_modules_data.txt')
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'
call set_gaussian(h, icenter, decay)
u = 0
!print *, 0, h
write (9, *) 0, h
close(9)
time_loop: do n = 1, num_time_steps
u = u - (u * diff(u) + g * diff(h)) / dx * dt
h = h - diff(u * (hmean + h)) / dx * dt
!print *, n, h
inquire(file = 'tsunami_simulator_with_modules_data.txt', exist = file_exists)
if (file_exists) then
open(9, file = 'tsunami_simulator_with_modules_data.txt', status = 'old', position = 'append', action = 'write')
else
open(9, file = 'tsunami_simulator_with_modules_data.txt', status = "new", action = 'write')
end if
write (9, *) n, h
end do time_loop
close(9)
end program tsunami
Program Explanation#
The following explanation is given by “Code Copilot” within ChatGPT 4.
The Fortran module mod_diff.f90
defines a module named mod_diff
that provides numerical differentiation functionalities tailored for use in simulations or numerical methods. Here’s an overview of its content:
Module: mod_diff
#
Dependencies: It uses the standard Fortran module
iso_fortran_env
for access to predefined kinds likeint32
for integers andreal32
for single-precision floating-point numbers.Functions:
diff_upwind(x)
: This function implements the upwind differencing scheme. It is used to approximate derivatives in problems where information propagates in one direction (like fluid flow in one direction). The outputdx
is a vector where each element is calculated as the difference between consecutive elements of the input vectorx
, except the first element, which is the difference between the first and last elements, simulating a wrap-around or periodic boundary condition.diff_centered(x)
: This function implements the centered differencing scheme, which is more accurate but also more sensitive to numerical errors. The function computes differences such that each element of the resultdx
is the difference between elements ofx
that are one step apart, with special handling for the first and last elements to manage boundary effects.
These functions are declared as pure
, which in Fortran ensures that they do not have side-effects, an essential property for functions that are intended to be used in parallel computations or where determinism is critical.
Both functions are designed to operate on arrays of single-precision floating-point numbers, indicating their intended use in applications where performance and memory usage are balanced against the precision of calculations.
This module can be used in larger Fortran programs or simulations where numerical differentiation is required, such as in fluid dynamics, weather modeling, or other computational physics simulations.
Let’s proceed to analyze the other files for a complete understanding of the entire program.
The Fortran module mod_initial.f90
defines a module named mod_initial
that includes functionality for initializing arrays based on specific patterns. Here’s an overview of its content:
Module: mod_initial
#
Subroutine:
set_gaussian(x, icenter, decay)
: This subroutine initializes an arrayx
with a Gaussian (or normal distribution) curve centered at the indexicenter
with a specifieddecay
rate. This pattern is commonly used in simulations for setting initial conditions where phenomena like wave packets or other localized features are described.
Details:#
Input/Output: The subroutine operates directly on the array
x
passed to it, modifying it in place (as indicated byintent(in out)
). This approach is typical in Fortran where arrays are often modified directly rather than returned.Parameters:
icenter
: An integer specifying the center position of the Gaussian distribution within the array.decay
: A real number that controls the width of the bell curve; higher values make the curve narrower.
Loop:
The Gaussian values are computed using a concurrent loop (
do concurrent
), which allows for parallel computation where supported. Each elementx(i)
is set toexp(-decay * (i - icenter)**2)
, which is the formula for a Gaussian function.
This module is particularly useful in simulations where initial conditions need to be defined in a spatially varying manner, such as setting up initial wave conditions in a medium or initial concentration distributions in simulations of diffusion processes.
We will next examine the main program file tsunami_simulator_with_modules.f90
to understand how these modules are utilized in a larger context.
The Fortran program tsunami_simulator_with_modules.f90
implements a simple model for simulating tsunami waves using numerical methods. Here’s a detailed explanation of the program:
Program Structure:#
Modules Used:
mod_diff
: Provides thediff_centered
function for numerical differentiation.mod_initial
: Contains theset_gaussian
subroutine for initializing wave heights.
Main Variables:
grid_size
: Defines the size of the grid (number of spatial points).num_time_steps
: Specifies the number of time steps for the simulation.dt
: Time step increment.dx
: Spatial step increment.g
: Gravitational constant (approximately 9.8 m/s²).hmean
: Mean height of the ocean layer.h
: Array representing the height of the wave at each grid point.u
: Array representing the velocity of the wave at each grid point.icenter
anddecay
: Parameters for the initial Gaussian distribution of the wave.
Operations:#
Initial Conditions: The water height array
h
is initialized using a Gaussian distribution centered aticenter
with a decay specified bydecay
. The velocity arrayu
is initialized to zero.Output File: Data is initially written to a file
tsunami_simulator_with_modules_data.txt
, and the wave height at each time step is appended to this file.Simulation Loop (
time_loop
):The velocities (
u
) are updated based on the gradient of the velocities and heights. The updates are scaled bydt/dx
to maintain stability and accuracy.The heights (
h
) are updated based on the divergence of the product of velocity and the sum of mean height and wave height. This mimics the conservation of mass in a fluid.
File Handling: Checks if the output file exists and writes data accordingly. If the file does not exist, it is created.
Numerical Methods:#
The simulation uses centered differences (
diff_centered
frommod_diff
) to compute spatial derivatives. Centered differences provide a good balance between accuracy and numerical stability.The time integration method appears to be a straightforward forward Euler method, which is simple but conditionally stable.
This program is an example of how modular Fortran programming can be used to build clean and maintainable scientific simulations. The use of separate modules for different functionalities (like initial condition setting and differentiation) makes the code easier to manage and modify.
Program Compilation and Execution#
The above program is compiled and run using Fortran Package Manager (fpm):
import os
root_dir = os.getcwd()
code_dir = root_dir + "/" + "Fortran_Code/Tsunami_Simulator_with_Modules"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")
exec_status = os.system("fpm run 2>/dev/null")
The above Fortran code writes the calculations to a file called tsunami_simulator_with_modules_data.txt
import pandas as pd
output_filename = 'tsunami_simulator_with_modules_data.txt'
data_file = code_dir + "/" + output_filename
table = pd.read_fwf(data_file, header=None)
table
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0.000010 | 0.000025 | 0.000063 | 0.000148 | 0.000335 | 0.000732 | 0.001534 | 0.003089 | 0.005976 | ... | 1.459711e-38 | 1.021038e-39 | 6.862018e-41 | 4.430906e-42 | 2.746545e-43 | 1.681558e-44 | 1.401298e-45 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 |
1 | 1 | 0.000012 | 0.000029 | 0.000071 | 0.000166 | 0.000372 | 0.000801 | 0.001661 | 0.003311 | 0.006346 | ... | 1.171803e-37 | 8.800796e-39 | 6.354580e-40 | 4.410867e-41 | 2.942727e-42 | 1.891753e-43 | 1.261169e-44 | 0.000000e+00 | 3.892368e-07 | 9.964396e-07 |
2 | 2 | 0.000015 | 0.000037 | 0.000089 | 0.000204 | 0.000447 | 0.000944 | 0.001921 | 0.003764 | 0.007097 | ... | 9.342945e-37 | 7.469310e-38 | 5.746058e-39 | 4.253277e-40 | 3.029047e-41 | 2.075323e-42 | 1.525808e-08 | 3.906043e-08 | 1.202751e-06 | 3.060115e-06 |
3 | 3 | 0.000021 | 0.000050 | 0.000118 | 0.000264 | 0.000566 | 0.001169 | 0.002327 | 0.004463 | 0.008249 | ... | 6.785309e-36 | 5.755973e-37 | 4.703170e-38 | 3.701251e-39 | 5.981168e-10 | 1.531169e-09 | 7.646778e-08 | 1.950150e-07 | 2.517209e-06 | 6.346270e-06 |
4 | 4 | 0.000030 | 0.000070 | 0.000161 | 0.000351 | 0.000736 | 0.001487 | 0.002896 | 0.005436 | 0.009836 | ... | 4.514822e-35 | 4.051931e-36 | 2.344618e-11 | 6.002181e-11 | 4.146878e-09 | 1.058688e-08 | 2.303804e-07 | 5.845143e-07 | 4.464170e-06 | 1.112178e-05 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
4996 | 96 | 0.178242 | 0.145647 | 0.101621 | 0.100381 | 0.122926 | 0.120063 | 0.123888 | 0.116525 | -0.085472 | ... | 3.023120e+00 | 5.041199e+00 | 4.517421e+00 | 2.471580e+00 | 9.274478e-01 | 2.414372e-01 | -1.293256e-02 | 1.105624e-01 | 1.427006e-01 | 1.615230e-01 |
4997 | 97 | 0.166096 | 0.137091 | -0.096517 | 0.101448 | 0.132967 | 0.122498 | 0.113014 | 0.109682 | -0.084616 | ... | 1.779129e+00 | 4.351381e+00 | 5.147950e+00 | 3.494045e+00 | 1.534592e+00 | 4.983789e-01 | 9.174558e-02 | -7.311907e-02 | 1.347228e-01 | 1.539230e-01 |
4998 | 98 | 0.150033 | 0.127765 | -0.095495 | 0.104681 | 0.140813 | 0.123673 | 0.101828 | 0.102024 | -0.084990 | ... | 7.355422e-01 | 3.197397e+00 | 5.167335e+00 | 4.501298e+00 | 2.378713e+00 | 9.002837e-01 | 2.534103e-01 | -1.492602e-02 | 1.189377e-01 | 1.425529e-01 |
4999 | 99 | 0.130618 | 0.118058 | -0.098317 | 0.109524 | 0.145394 | 0.123321 | -0.091511 | -0.094122 | -0.086058 | ... | 2.072203e-02 | 1.919918e+00 | 4.503167e+00 | 5.186921e+00 | 3.417265e+00 | 1.503764e+00 | 5.057256e-01 | 7.775510e-02 | -8.935884e-02 | 1.256339e-01 |
5000 | 0 | 0.108276 | 0.108241 | 0.104191 | 0.115224 | 0.146075 | 0.121337 | -0.083074 | -0.086573 | -0.087238 | ... | 3.938838e-01 | 8.310862e-01 | 3.336946e+00 | 5.263032e+00 | 4.469062e+00 | 2.348540e+00 | 8.970855e-01 | 2.271172e-01 | -3.692843e-02 | 1.003862e-01 |
5001 rows × 101 columns