Fortran

Guide To Learn

Here, we’ll focus on writing a brand new module, and defining the finite difference function in it. When we’re done, we’ll be able to import this function from the module and use it in the main program. Start by opening a brand-new source file, mod_diff.f 90. Once you’re in the file, you can define the module scope with module and end module statements:

module mod_diff         ❶
end module mod_diff     ❷

❶ Begins the module definition and specifies its name

❷ Ends the module definition

Nothing exciting here so far–we defined a module and gave it a name. Like programfunction, and subroutine statements, a module statement must be matched with a corresponding end module statement. Anything that we define between the module and end module statements will belong to the module.

I mentioned earlier that we’ll define our new module in its own Fortran source file. How to name your source files is a matter of style. I like to name my module files starting with mod_. This tells me that the file defines a module, and the following word or words in the file name tell me what the module is about. For the finite difference functions, I’ll just use mod_diff.f 90, as I said before, and for the set_gaussian, I’ll use mod_initial.f 90 because a Gaussian shape is a kind of initial condition. Although multiple modules in a single file are allowed, I recommend keeping one module per source file.

Tip Define one module per source file.

Our mod_diff module isn’t useful at all yet because we didn’t define any variables or procedures in it. Let’s do that now. Recall from the previous chapter how we used the contains statement to define our new procedures in the body of the main program, as shown in the following listing.

Listing 4.2 Procedure definitions follow the contains statement

program tsunami         ❶
  ...                   ❷
contains                ❸
  ...                   ❹
end program tsunami     ❺

❶ Opens the program scope

❷ Variable declarations and executable code go here.

❸ Separates the executable code from the procedure definitions

❹ Defines external procedures here

❺ Closes the program scope

Defining them in the main program is a reasonable solution while our tsunami simulator is still rather simple. However, the code will soon become hard to manage as we define more and more procedures. This is where modules come in to help us organize our code in a meaningful way.

Defining variables and procedures in a module works the same way as for the main program, as shown in the following listing.

Listing 4.3 Using the contains statement to define procedures in the body of a module

module mod_diff       ❶
  ...                 ❷
contains              ❸
  ...                 ❹
end module mod_diff   ❺

❶ Opens the module scope

❷ Variable declarations go here.

❸ Separates the variable definitions from the procedure definitions

❹ Defines external procedures here

❺ Closes the program scope

If you compare this bare-bones snippet to the one from listing 4.2, you’ll see that I only replaced the program/end program with module/end module (and their names, of course). One important difference from the main program, functions, and subroutines, is that the module can only contain declarative code, not executable code. This means that you can’t run a module like a program, or call it like you can a function or subroutine. What you can do is access any public entity, be it a variable, a function, or a subroutine, that’s made accessible by the module. I’ll get into what I mean by public in a little bit.

Let’s go ahead and define our diff function inside the module. While we’re at it, we’ll also use the portable type kinds that we learned about earlier in this chapter. The complete code listing is as follows.

Listing 4.4 Custom module that defines the finite difference function

module mod_diff
 
  use iso_fortran_env, only: int32, real32     ❶
  implicit none                                ❷
 
contains
 
  pure function diff(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
 
end module mod_diff

❶ Imports portable type kinds from the built-in module

❷ The explicit declaration applies to the entire module.

❸ Defines the function after the contains statement

And that’s it, your first custom Fortran module. In the first part, before the contains statement, we import the type kinds from the iso_fortran_env module, and require explicit declaration using implicit none. When implicit none is used in the module scope, it applies to everything within the module and end module statements, so we don’t need to specify it again in functions or subroutines. Finally, after the contains statement, we include our function definition, which I copy-pasted from the main program.

To access the diff function in the main program, we need to add one line at the beginning, immediately before the implicit none:

program tsunami
 
  use mod_diff, only: diff     ❶
  implicit none
  ...

❶ Imports the diff function from the mod_diff module

Now that we have a module in its own source file, and a main program in another, let’s see how we can compile these two together into a single executable program.

Defining a module

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top