Question

I am a researcher working with a program written in Fortran. I have very basic coding skills, so I need a bit of help getting some code to compile properly.

I will give a bit of background before showing the code. I am dealing with a large number of data, which will require 64-bit compiling and greater than 2 gb of memory. The first thing I noticed in the code is that many of the variables were written as "real", but in my research I found that "double precision" allows for much larger variables, and would be a more flexible choice, so I changed all "real" variables to "double precision" variables.

There is also in a file that is included in the compilation of the fortran build file "dist.f", called "geocoord.inc". I found that the variables are saved to a common block, but once again, I need something that can hold a larger amount of data. As I have been led to believe, a module would be a better program to use. I need some advice in converting this include file to work properly with the module program, which I will list below.

Dist.f:

c Convert latitude and longitude to kilometers relative
c to center of coordinates by short distance conversion.

subroutine dist(xlat, xlon, xkm, ykm)

implicit none

c   Parameters:
double precision    xlat, xlon  ! (input)
double precision        xkm, ykm    ! (output)

c   Local variables:
double precision lat1, lat2, lat3
double precision    q
double precision    xx
double precision    yp

include "geocoord.inc"

c Set up short distance conversion by subr. SETORG
  q=60*xlat-olat
  yp=q+olat
  lat1=datan(rlatc*dtan(RAD*yp/60.0))
  lat2=datan(rlatc*dtan(RAD*OLAT/60.0))
  LAT3=(LAT2+LAT1)/2.
  xx=60*xlon-olon  !  - wegen LON E
  q=q*aa
  xx = xx*bb*dcos(LAT3)
  IF(rotate.ne.0.) then
c** rotate coordinate system anticlockwise
    yp=cost*q+sint*xx
    xx=cost*xx-sint*q
    q=yp
  ENDIF

  xkm=xx
  ykm=q

  return
  end

Geocoord.inc:

double precision rearth
double precision ellip
double precision rlatc
double precision rad
double precision olat, olon
double precision aa, bb, bc
double precision sint, cost
double precision rotate
integer icoordsystem

common /GEO_COORSYSTEM/ rearth, ellip, rlatc, rad,
&    olat, olon, aa, bb, bc, sint, cost, rotate,
&    icoordsystem

I appreciate any advice that you can provide and apologize for my relative ignorance in all things Fortran!

Was it helpful?

Solution

Modernizing an old code is often not an easy task. At least for a beginner. The move from real to double precision is not in the spirit of modern Fortran, but until you introduce modules it is OK. When you have modules it is better to do:

module precisions
  integer, parameter :: rp = kind(1.d0) !if you insist on double, otherwise use selected_real_kind()
end module

and everywhere use the new kind constant that denotes your real precision:

  use precisions

      real(rp) :: variables

With the common blocks, the one you showed would be:

module geo_coordsystem
  use precisions

  implicit none

  real(rp) :: rearth
  real(rp) ::  ellip
  real(rp) ::  rlatc
  real(rp) ::  rad
  real(rp) ::  olat, olon
  real(rp) ::  aa, bb, bc
  real(rp) ::  sint, cost
  real(rp) ::  rotate
  integer icoordsystem

end module

Then you use it:

subroutine dist(xlat, xlon, xkm, ykm)
  use precisions
  use geo_coordsystem

  implicit none

You can also continually move you subroutines to modules. Do that in small steps and always check that you didn't introduce some bug.

OTHER TIPS

Several Fortran compilers have an option to promote real variables to double precision. In gfortran the option is -fdefault-real-8 , as documented at http://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html . In the long run it is better to use kinds as Vladimir F suggested.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top