Search code examples
fortranfortran90intel-fortran

error #6451: A dummy argument name is required in this context


I'm getting a weird error when compiling my simulation code written in Fortran 90, I was hoping to get some help by any chance. I'm using ifort version 18.0.3.

Before telling the problem, here's what I have that are working properly: Below module prng is a pseudo-random number generator(it's in fortran 77 but I have tested it just in case any compatibility concerns, it works fine!):

  module prng

  implicit none

  contains
   real*8 function genrand_real( ir )
   implicit real*8 (a-h,o-z)

   integer, intent(inout) :: ir
   parameter(da=16807.d0,db=2147483647.d0,dc=2147483648.d0)
   ir = abs(mod(da*ir,db)+0.5d0)
   genrand_real = dfloat(ir)/dc

   return
   end function genrand_real

  end module prng

I also created a module in order to declare the seed:

  module seed
    implicit none

    type mod_seed

       integer :: seedvalue

    end type mod_seed
  end module seed

In order to use seedvalue, type(mod_seed) :: seedval needs to be declared first, then genrand_real(seedval%seedvalue) returns a real value in (0,1).

So far above mentioned are all working fine! Below is what I'm trying to implement, basically I adopted a gaussian deviate function, function gauss_dev() result(harvest), from Numerical recipes in Fortran (page 280), see the source code below:

 module moves

  use prng
  use seed

  implicit none

  contains

  function gauss_dev() result(harvest)

    implicit none
    real(kind=8) :: harvest
    real(kind=8) :: rsq,v1,v2
    real(kind=8), save :: g
    logical, save :: gauss_stored = .false.

    if (gauss_stored) then
        harvest = g
        gauss_stored = .false.
    else
        do
            v1 = genrand_real(seedval%seedvalue)
            v2 = genrand_real(seedval%seedvalue)
            v1 = 2.0*v1-1.0
            v2 = 2.0*v2-1.0
            rsq = v1**2 + v2**2
           if (rsq > 0.0 .and. rsq < 1.0) exit
        enddo

        rsq = sqrt(-2.0*log(rsq)/rsq)
        harvest = v1*rsq
        g = v2*rsq
        gauss_stored = .true.

    endif
end function gauss_dev

! also other subroutines that calls gauss_dev()
end module moves    

The seedval%seedvalue is initialised by

   subroutine read_iseed(seedval,IN_ISEED)
    use prng
    use seed

    type (mod_seed), intent(inout) :: seedval
    character(len=80) :: IN_ISEED
    integer :: i

    call system('od -vAn -N4 -td4 < /dev/urandom > '//trim(IN_ISEED))
    open(unit=7,file=trim(IN_ISEED),status='old')
    read(7,*) i
    close(7)
    seedval%seedvalue = abs(i)

    return
   end

When I compile the code, I get an error message: error #6404: This name does not have a type, and must have an explicit type. [SEEDVAL], this is expected as the seedvalue must be declared before calling!

Since the seedvalue gets reassigned in prng, intuitively I'd use intent(inout) option. And here's my fix:

  module moves

  use prng
  use seed

  implicit none

  contains

  function gauss_dev() result(harvest)

    implicit none
    type (mod_seed), intent(inout) :: seedval
    real(kind=8) :: harvest
    real(kind=8) :: rsq,v1,v2
    real(kind=8), save :: g
    logical, save :: gauss_stored = .false.

    if (gauss_stored) then
        harvest = g
        gauss_stored = .false.
    else
        do
            v1 = genrand_real(seedval%seedvalue)
            v2 = genrand_real(seedval%seedvalue)
            v1 = 2.0*v1-1.0
            v2 = 2.0*v2-1.0
            rsq = v1**2 + v2**2
           if (rsq > 0.0 .and. rsq < 1.0) exit
        enddo

        rsq = sqrt(-2.0*log(rsq)/rsq)
        harvest = v1*rsq
        g = v2*rsq
        gauss_stored = .true.

    endif
end function gauss_dev

! also other subroutines that calls gauss_dev()
end module moves    

However when I compile the code, I get error message:

  error #6451: A dummy argument name is required in this context.   [SEEDVAL]
    type (mod_seed), intent(inout) :: seedval

I'm not certain what caused the error. But as I was randomly trying with intent()options, I accidentally found out that without specifying intent(), the code gets compiled WITHOUT errors, which is weird because I thought without specifying intent(), fortran compiler takes inout as the default option? But as a result of NOT specifying intent(), the simulation gets stuck in the do-loop:

       do
            v1 = genrand_real(seedval%seedvalue)
            v2 = genrand_real(seedval%seedvalue)
            v1 = 2.0*v1-1.0
            v2 = 2.0*v2-1.0
            rsq = v1**2 + v2**2
           if (rsq > 0.0 .and. rsq < 1.0) exit
       enddo

because seedval%seedvalue returns 0, which causes rsq constantly failing if (rsq > 0.0 .and. rsq < 1.0) exit condition.

Before posting this thread, I read Fortran intent(inout) versus omitting intent, I see the potential compatibility issue out there, but that's introduced since Fortran 2003 according to the thread.

Coming to the end I bear two questions: 1. In fortran 90, is there a difference between specifying intent(inout) and not specifying at all? 2. In regard to the error message when specifying intent(inout), what's the cause of it?

Any hint would be appreciated!


Solution

    1. In fortran 90, is there a difference between specifying intent(inout) and not specifying at all?

    Yes: already in the Fortran 90 standard, a dummy argument with intent(inout) needed to be definable, and this was not a requirement for dummy arguments without an intent attribute, see section 5.1.2.3 of the Fortran 90 standard.

    Before posting this thread, I read Fortran intent(inout) versus omitting intent, I see the potential compatibility issue out there, but that's introduced since Fortran 2003 according to the thread.

    Please read that thread more carefully, while they do discuss the issue citing Fortran 2003 references, at no point they say anything about this being introduced in the 2003 version of the standard.

    1. In regard to the error message when specifying intent(inout), what's the cause of it?

    When you did not specify the intent of seedval and you didn't list seedval as a dummy argument of the function, the compiler thought that seedval was a local variable and was happy with it. The moment you defined an intent for seedval, without listing it as a dummy variable, the compiler was naturally unhappy (intent can only be provided for dummy arguments), so it raised the error.

    with/without having intent(inout) specified, code returns different results, any clue?

    Maybe I am missing it, but can you please clarify where you initialize seedval%seedvalue? If you are using an uninitialized variable, that would easily explain why different compilations produce different values.


    If I follow your description of the issue correctly (please correct me otherwise), your code only ran when either (a) seedval was not listed as a dummy argument of function gauss_dev, and it didn't have an intent attribute; or (b) seedval was listed as a dummy argument of the function and it had intent(inout).

    The code had a very different behaviour in (a) and (b) because in (b) the component seedval%seedvalue had been appropriately initialized by your read_iseed subroutine, while in (a) seedval was a variable local to gauss_dev, which was being used by genrand_real before being initialised. In this case, the compiler was probably initialising seedval%seedvalue to zero in gauss_dev, and your genrand_real function returns zeroes (for both ir and genrand_real) when variable ir is zero at input, hence the infinite loop you described.

    Note that multiple runs of a binary compiled following (b) will most likely produce different numerical results, since the system call you make within read_iseed

    od -vAn -N4 -td4 < /dev/urandom
    

    will usually return different integer values for your seed.