Buscar

Improve Fortran 77 Programs Using Fortran 90

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 9 páginas

Prévia do material em texto

04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 1/9
Improve your Fortran 77 programs using some
Fortran 90 features
This essay is under construction.
Ryo Furue (Email: my family name AT hawaii PERIOD edu)
There are already many tutorials exploring various features of the Fortran 90 (F90) language in a
systematic way. Instead of adding yet another tutorial of such kind, I here focus on how to improve
your Fortran 77 (F77) programs by using small subsets of the F90 language. To do so, I'll show small
code in F77, point out problems in it, and propose a solution or improvement using some features of
F90.
I think this approach is useful to convince scientists that F90 is useful and easy to adopt. I've found
persistent resistance among fellow scientists against F90, reasons for the resistance including
1. Benefits of F90 aren't clear ("Why bother?").
2. F90 is a large, complex language.
3. Transition to F90 would require a lot of efforts.
4. F90 compilers may not be available everywhere.
My answers to these issues are simple:
1. F90 will cut down your efforts in debugging your code (you get results more quickly).
2. You have only to learn a small subset of the F90 language;
3. Your choice is not F77 or F90; rather, you mix a bit of F90 in your F77 programs. You don't
have to convert existing F77 programs; rather, when you modify them, you can mix in some
F90 features.
4. It's hard to find a F77­only compiler nowadays; and free F90 compilers are easier to find than
F77­only ones.
To me, the situation is similar to the following fictitious conversation:
A: It's hard to climb up to this floor everyday.
B: But, why don't you use the elevator?
A: Um, I heard it's for expert building­climbers. I just have to climb it once a day, so it's
not worth it to learn the new technology.
If you find this conversation funny, you understand how I feel.
Mismatched COMMON blocks
Problem
  subroutine sub1 
    common /pars/a, b, d 
    ! . . . . . 
  end 
  subroutine sub2 
    common /pars/a, b, c, d 
    ! . . . . . 
  end 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 2/9
You sometimes modify a COMMON block in one subroutine and forget to update other subroutines
using the COMMON block. This error often leads to a long debug session.
What's the problem? The fundamental source of the problem is that you have identical information at
many places. (This is a recurring theme as we'll see.)
A minimal solution
Put the COMMON block in a MODULE and USE it elsewhere:
  module pars_mod 
    common /pars/a, b, d 
    save 
  end module pars_mod 
  subroutine sub1 
    use pars_mod 
    ! . . . . . 
  end 
  subroutine sub2 
    use pars_mod 
    ! . . . . . 
  end 
Here, the original problem does not exist, because its source (repetition of the same information) is
gone.
A better solution
In fact, it's better to avoid COMMON blocks altogether. The solution above can be rewritten as
  module pars_mod 
    real a, b, d 
    save 
  end module pars_mod 
  subroutine sub1 
    use pars_mod 
    ! . . . . . 
  end 
  subroutine sub2 
    use pars_mod 
    ! . . . . . 
  end 
Details
You may have noticed the SAVE statements in the MODULEs above. You might think this is an extra
complication in F90. It's not. In fact you usually have to save COMMON variables in F77, too. Did
you know that? Indeed, situations where you need to save COMMON variables are the same as those
where you need to save MODULE variables. When you have to save and when you don't is a
complicated subject, which I don't want to discuss here. Don't worry. Since you want COMMON and
MODULE variables to be saved 99% of the time, it's safe always to save them.
"Wait," I hear you say, "I've never used SAVE but my COMMON blocks have always worked for
me." Right. For the same reason, your MODULE variables usually work without SAVE­ing them. I
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 3/9
just recommend using SAVE, to be on the safe side.
Initial values of COMMON variables
Problem
How do you give initial values to COMMON variables? You might assign values to them in a
subroutine:
  subroutine sub1 
    common /pars/a, b 
    a = 3.14 
    b = ‐999.0 
    ! . . . . . 
  end 
  subroutine sub2 
    common /pars/a, b 
    common /foos/kk, mm 
    kk = ‐1 
    mm = 10 
    !. . . use a, b, kk, and mm . . . 
  end 
But, what if you forget to call sub1 before calling sub2 ? That's bad, because in sub2, those variables
won't have proper values. Also, it's hard to keep track of who initializes which COMMON variables.
In the example above, sub1 initializes a and b and sub2 initializes kk and mm. If you have many
COMMON blocks, this would be pretty messy. Or you might use DATA statements:
  subroutine sub1 
    common /pars/a, b 
    data a/3.14/, b/‐999.0/ 
    ! . . . . . 
  end 
  subroutine sub2 
    common /pars/a, b 
    common /foos/kk, mm 
    data kk/‐1/, mm/10/ 
    ! . . . . . 
  end 
But, still you aren't sure whether or not a and b are initialized in sub2. The problem of who initializes
what isn't solved, either.
You can guarantee the initialization of COMMON variables by putting all COMMON blocks and
their initializations to the main program:
  program main 
    common /pars/a, b 
    common /foos/kk, mm 
    data a/3.14/, b/‐999.0/ 
    data kk/‐1/, mm/10/ 
    . . . . . 
  end   
  subroutine sub1 
    common /pars/a, b 
    . . . use a and b . . . 
  end 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 4/9
  subroutine sub2 
    common /pars/a, b 
    common /foos/kk, mm 
    !. . . use a, b, kk, and mm . . . 
  end 
As a result, you end up with having all COMMON blocks in the main program, whether you use them
in the main program or not. Your program becomes the messier for that.
The best solution within F77 to this problem is to use a BLOCK DATA.
  block data 
    common /pars/a, b 
    common /foos/kk, mm 
    data a/3.14/, b/‐999.0/ 
    data kk/‐1/, mm/10/ 
  end 
  subroutine sub1 
    common /pars/a, b 
    !. . . use a and b . . . 
  end 
  subroutine sub2 
    common /pars/a, b 
    common /foos/kk, mm 
    !. . . use a, b, kk, and mm . . . 
  end 
You initialize all COMMON blocks in a single BLOCK DATA. At least, we have solved the original
problems: The COMMON variables are guaranteed to be initialized before any subroutines are called,
and it is now clear that initial values are all given in the BLOCK DATA.
This solution, however, still has a problem of the repetition of the same information. For example, if
you introduce another common block, or another variable in an existing COMMON block, you have
to edit the BLOCK DATA, too, which you sometimes forget.
Solution
When the two COMMON blocks in the problem above aren't much related, it's natural to put them in
different MODULEs:
  module pars_mod 
    real:: a = 3.14, b = ‐999.0 
    save 
  end module pars_mod 
  module foos_mod 
    integer:: kk = ‐1, mm = 10 
    save 
  end module foos_mod 
  subroutine sub1 
    use pars_mod 
    !. . . use a and b . . . 
  end 
  subroutine sub2 
    use pars_mod 
    use foos_mod 
    !. . . use a, b, kk, and mm . . . 
  end 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 5/9
This solution is much cleaner than the F77 counterpart for a few reasons. First, the definition of
variables and their initial values are close together:
    real:: a = 3.14, b = ‐999.0 
Second, therepetition of information is reduced. Finally, you can keep related variables in a single
place and unrelated variables separated; in the example above, a and b are put in one MODULE and
kk and mm are in another.
The last point is another important, recurring theme: Related information should be put in one place
and unrelated information, separated. That will lead to a better organized (and therefore easier to
understand) program.
More initialization of COMMON variables
Problem
In the example above, the initialization of COMMON variables have been just assignments of
constants. What if you need more than just assignments to initialize those variables? For example, you
sometimes need to conduct some computation to determine initial values for COMMON variables.
BLOCK DATA cannot be used because it cannot contain any executable statements. In that case, your
best solution within F77 would be
  subroutine init_pars 
    common /pars/a, b 
    ! . . . . . . 
    read(. . .) dd, ee 
    call compute_a_b(a, b,  dd, ee) 
  end 
  subroutine compute_a_b(a, b,  dd, ee) 
    ! . . . . . . 
  end 
  program main 
    call init_pars 
    ! . . . . . . 
  end 
  subroutine sub1 
    common /pars/a, b 
    ! . . . use a and b 
  end 
This isn't bad. But, it's better to put the information concerning the variables a and b together (better
organization).
Solution
MODULEs can contain not only variables but also subroutines:
  module pars_mod 
    real a, b 
    save 
  contains 
    subroutine init_pars 
      . . . . . . 
      read(. . .) dd, ee 
      call compute_a_b(a, b, dd, ee) 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 6/9
    end subroutine init_pars 
    subroutine compute_a_b(a, b, dd, ee) 
      ! . . . . . . 
    end subroutine compute_a_b 
  end module pars_mod 
  program main 
    use pars_mod 
    call init_pars 
    . . . . . . 
  end 
  subroutine sub1 
    use pars_mod 
    . . . use a and b . . . 
  end 
Now, MODULE pars_mod contains everything related to variables a and b.
Constants
Problem
You often need to use constants at various places in your program. How should you define and use
them? The worst strategy is
  subroutine sub1 
     . . . . . . 
     a = b * 1000 
  end 
  subroutine sub2 
     . . . . . . 
     d = e / 1000 
     . . . . . . 
     k = i + 1000 
  end 
What's this magic number 1000 ? What if you later need to change its value? Should you change all
occurrences of the value 1000 ? or do some of the occurrences have different meanings? The source
of this problem is again the repetition of information.
A better approach is to give the value a name and use the latter throughout your program:
  subroutine sub1 
    parameter (nx = 1000) 
    . . . . . . 
    a = b * nx 
  end 
  subroutine sub2 
    parameter (nx = 1000) 
    parameter (mode = 1000) 
    . . . . . . 
    d = e / nx 
    . . . . . . 
    k = i + mode 
  end 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 7/9
Now, it's clear that the two occurrences of 1000 in sub2 have different meanings, so that even if you
need to change the value of nx, you won't make the mistake of changing the value of mode.
The program above still has a problem: When you change the value of nx, you may forget to do so in
some of the subroutines. Repetition of information hurts, again.
Solution
You put the definition of constants into a MODULE:
  module pars_mod 
    parameter (nx = 1000) 
  end pars_mod 
  subroutine sub1 
    use pars_mod 
    . . . . . . 
    a = b * nx 
  end 
  subroutine sub2 
    use pars_mod 
    parameter (mode = 1000) 
    . . . . . . 
    d = e / nx 
    . . . . . . 
    k = i + mode 
  end 
Now, you have only to change the value of nx in MODULE pars_mod. Notice that I didn't put the other
constant (mode) in a MODULE. That's okey if the constant is used only in sub2.
Sharing values among subroutines
Problem
Subroutines sometimes need to share a lot of values. Should we pass them as arguments to the
subroutines?
  subroutine sub1(a, b, p, q, r, s, t, u) 
    ! . . . use p, q, r, s, t, and u . . . 
  end 
  subroutine sub2(kkk, p, q, r, s, t, u) 
    ! . . . use p, q, r, s, t, and u . . . 
  end 
  subroutine othersub(x, y, z, p, q, r, s, t, u) 
    ! . . . Doesn't use p, q, r, s, t, u . . . 
    call sub2(kkk, p, q, r, s, t, u) 
  end 
  program main 
    p = 3.14 
    q = ‐999.0 
    r = p + 3*q 
    read(*,*) s 
    t = s * p 
    u = t * t + s 
    call sub1(a, b,        p, q, r, s, t, u) 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 8/9
    call othersub(x, y, z, p, q, r, s, t, u) 
  end 
This style will quickly become cumbersome. You have to pass all the shared variables down to all
subroutines requiring them. In particular, look at othersub, which needs to receive those variables and
pass them onto sub2, even though othersub itself doesn't use them.
You are therefore tempted to use COMMON blocks to avoid this problem:
  subroutine sub1(a, b) 
    common /pars/p, q, r, s, t, u 
    ! . . . use p, q, r, s, t, and u . . . 
  end 
  subroutine sub2(kkk) 
    common /pars/p, q, r, s, t, u 
    ! . . . use p, q, r, s, t, and u . . . 
  end 
  subroutine othersub(x, y, z) 
    ! . . . . . 
    call sub2(kkk) 
  end 
  program main 
    common /pars/p, q, r, s, t, u 
    p = 3.14 
    q = ‐999.0 
    r = p + 3*q 
    read(*,*) s 
    t = s * p 
    u = t * t + s 
    call sub1(a, b) 
    call othersub(x, y, z) 
  end 
This is an improvement. It is now clear that othersub has nothing to do with p, q, r, s, t, or u. Still, this
isn't good enough: The fact that sub1 and sub2 share the variables isn't clear; the fact that othersub
doesn't care about them isn't clear; nor is it clear who is responsible for the values of the shared
variables.
Solution
You put the shared variables and subroutines that use them into a MODULE:
  module mysubs 
    real, private:: p, q, r, s, t, u 
    save 
  contains 
    subroutine init_mysubs 
      p = 3.14 
      q = ‐999.0 
      r = p + 3*q 
      read(*,*) s 
      t = s * p 
      u = t * t + s 
    end subroutine init_mysubs 
    subroutine sub1(a, b) 
      ! . . . use p, q, r, s, t, and u . . . 
    end subroutine sub1 
04/02/2016 Improve Fortran 77 Programs Using Fortran 90
http://iprc.soest.hawaii.edu/users/furue/improve­fortran.html 9/9
    subroutine sub2(kkk) 
      ! . . . use p, q, r, s, t, and u . . . 
    end subroutine sub2 
  end module mysubs 
  subroutine othersub(x, y, z) 
    use mysubs 
    ! . . . . . 
    call sub2(kkk) 
  end 
  program main 
    use mysubs 
    call init_mysubs 
    call sub1(a, b) 
    call othersub(x, y, z) 
  end 
Now, all the problems stated above are solved. 1) It's clear that p, q, r, s, t, and u are shared only by
sub1 and sub2; 2) It's clear who is responsible for determining their values; 3) It's clear that othersub
has nothing to do with them.
Details
Notice the PRIVATE keyword in the MODULE, which indicates that those variables are accessible
only within the MODULE, implying that the MODULE is exclusively responsible for them. The
PRIVATE specification isn't necessary, but it's better to have it if the variables aren't used outside the
MODULE. Without it, the variables can be changed from outside the MODULE, a possibility that it's
better to avoid.
More to come if I find the time . . .
. . . . . . . . .
Acknowledgments
Thanks to Zuojun.

Outros materiais