4

Currently in my program I have several common blocks spread across several subprograms and functions. I sometimes forget to change all instances of a common block as I add variables to it. I want to make these common blocks into modules so I can add and remove variables to the module in one place without worrying about updating all instances of the module across my subprograms.

Do I need to include 'use' statements in the program that initializes the variables in the module or do I include the program in the module? I normally would use common blocks for this but am trying to implement modules because I think they will help my code remain readable as complexity increases.

NOTE: Some values of the variables in the modules need to be able to change as they are passed from one program to another.

I tried to write a simplified test program to become acquainted with modules but could not get it to work. I am familiar with fortran 77 but have never used modules before. I appreciate any help or advice.

I am using gfortran 4.6.1

Main.f

program main
use Words
use Vals
double precision x,y,z
character*5 Greet
integer i

Greet = 'Hello'
x = 4.1
y = 5.2
z = 10.0
i = 3

call foo ()

end program main

subroutine foo ()
use Words
use Vals

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer int
save
end module
AstroCB
  • 12,337
  • 20
  • 57
  • 73
kxk7607
  • 207
  • 1
  • 4
  • 10

3 Answers3

5

You only need one instance of a module. You make it known to any main program or procedure (subroutine or function) that uses it with a use statement. If you have a subroutine that sets values then, like any other, it has to have a use statement. If are are setting initial values you can do so in the declaration. If the module is used by the main program then it will always be in scope and the values of the variables will persist throughout the run of the program. If the module is only used by procedure, in principle the module will go out of scope when none of those procedures are in the call chain and the compiler is allowed to forget the values of the module variables. (It is doubtful that any Fortran compiler actually does this.) This can be prevented by declaring each variable with SAVE. SAVE is implicit if you declare the variable with an initial value.

Normally you have to compile the modules first before they are used so that the compiler "knows" about them when it encounters the use statement. This is done either by putting them first in the file or compiling their files first. Here is your example reordered:

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer i
save
end module

module my_subs

contains

subroutine foo ()
use Words
use Vals
double precision :: z

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

end module my_subs


program main
use Words
use Vals
use my_subs


Greet = 'Hello'
x = 4.1
y = 5.2

i = 3

call foo ()

end program main
M. S. B.
  • 28,968
  • 2
  • 46
  • 73
  • 1
    Since fortran 2003 (or was it 2008?) all module variables are automatically saved. – eriktous Jan 10 '13 at 17:14
  • This was very helpful. Thank you. Hopefully over the weekend I can successfully implement modules into my program. – kxk7607 Jan 11 '13 at 23:15
  • Is the use of modules preferred over the use of `include`? I currently have many 'include' statements at the end of my MAIN. It is my understanding that included subroutines are implicitly accessible to one another. Is this a correct understanding? Should I implement modules instead? I already have the program working but if the use of modules will make it easier for people to work edit my program in the future then I will take the time to implement them. – kxk7607 Jan 17 '13 at 23:47
  • If you are placing your subroutines after the main program with a contain statement, I recommend placing them in a module instead. First, subroutines after a contain statement in a main program inherit the variables of the main program that aren't masked by their local variables. This can be very confusing. Second, having the subroutines in a module allows them to be reused in other programs. Finally, uou can also group module variables and subroutines into various modules by logical relationships. – M. S. B. Jan 18 '13 at 06:30
  • I am using `include` statements not `contain` statements (is there a difference?). The end of my MAIN looks like this `end program main include "./SUBROUTINES/Sub1.f" include "./SUBROUTINES/Sub2.f"` Each subroutine is in a separate file. Would using modules help? Most of the subroutines are written in ANSI standard fortran 77. I am going to have to read up on module syntax and nesting because I only understood about 1/2 of what you said! You have given me a good starting point though. – kxk7607 Jan 18 '13 at 20:43
  • 1
    Placing subroutines into modules and then "use"ing them is very useful because it enables the compiler to check for consistency between the actual arguments and the dummy arguments, i.e., between the arguments in the call and the arguments of the subroutine declarations. This way the compiler catches a lot of programmer mistakes and programming is quicker. – M. S. B. Jan 19 '13 at 22:25
  • I have a function `func`, a subroutine `subrout`, and a main `main`. I want to pass values between `func` and `subrout` but do not necessarily need `main` to have access to these values. I plan to make a module called `subfunc` and place `func` and `subrout` inside this module. I then place the `use subfunc` at the top of main where I also define a module called `vals`. I place `use vals` right after the subroutine and function declarations for `subrout` and `func` under the module `subfunc` but do not include `use vals` in `main`. Does this example present a correct understanding of modules? – kxk7607 Jan 21 '13 at 16:33
  • Yes. An alternative that allows you to control access/visibility of items but avoid proliferation of modules is to limit the items accessed on the `use` statement with the `only` option. – M. S. B. Jan 22 '13 at 09:50
1

There are a couple of reasons why your code will not compile:

  1. You have your modules positioned after your main program, which means they will not have been compiled by the time you use them there. Either put these in separate files and compile them before the main program, or put them before the main program.

  2. You re-declare variables from your module in the main program, which the compiler will interpret as a name conflict. All module variables with the public attribute (which is the default) will become available in the scope where you use the module; this is called "use association". In other words, use vals is enough to make x, y and int available.

Additionally, modules are more like singleton objects rather than just data containers. They can also contain procedures, listed after a contains statement, which aids grouping variables and related procedures together. An example would be grouping your two modules into one, along with subroutine foo:

module vals
  implicit none

  double precision :: x = 4.1, y = 5.2
  integer :: i = 3
  character(5) :: greet = 'Hello'

contains
  subroutine foo()
    double precision :: z  ! New local variable

    print *, Greet

    z = x + y
    print *, z

    print *, i
  end subroutine
end module

Above, I have used the "new" :: double colon operator, which allows declaring and initialising multiple variables at once. Since module variables are already save'd implicitly, this is just fine.

Alternatively, if these modules are intended to be separate, you can also have contains sections in your main program (or any subprogram) and place the subroutine there. The advantage is that procedures declared in such a way always have explicit interfaces, which greatly benefits error diagnosis by the compiler and is even required in certain newer cases. This is one of the main improvements of F90, since F77 only dealt with external subprograms and implicit interfaces.

sigma
  • 2,758
  • 1
  • 14
  • 18
  • 1
    Oh darn, walked away for a bit and didn't see MSB's answer. Apologies from the Department of Redundancy Department. – sigma Jan 10 '13 at 17:30
-1

The simplest way to do common blocks is to have one include file per common block and make all your declarations within the include file. That way, the common block is only ever declared in one place. The problem of having to convert the code to use modules then just magically disappears.

Also, if you are starting new code, prefixing the name of the common block variables with the same name as the named common block will make coding a lot easier. It is a pain initially and the prima donnas who have been coding for years will refuse to conform. The people who maintain the code will just find it so easy: no greps or groks. Just by looking at the name, you know which common block it comes from.

Keeping the same convention with modules also helps. If all routine names and variable names begin with the module name, then just by looking at the name, you know which module it comes from.

cup
  • 7,589
  • 4
  • 19
  • 42
  • 1
    This is very poor advice. It's especially poor within the context of the question and accepted answer here, OP is already rewriting to modules. Used properly they are a far better approach than common blocks and include statements. Converting code to use modules isn't a problem, it's an opportunity to enhance code. – High Performance Mark Mar 17 '13 at 09:38