Vince W.
Vince W.

Reputation: 3785

Is it possible to initialize a Fortran parameter array with a loop expression?

I have a constant array that I would like to use, but I would prefer not to have to use an initialization call to set it up, rather it would be preferable to have it be a parameter. However, I haven't been able to figure out the correct syntax, assuming that it is possible, or to confirm that it is not possible.

Example code below. Is it possible?

module mymod
  implicit none
  private
  public initmymod, printinit

  integer, parameter :: n=11
  real, parameter :: startval=10.,stopval=20.,step=(stopval-startval)/(n-1)

  ! would rather use something like this parameter statement than a protected array, is it possible?
  ! real, parameter :: vals_p(n) = startval+(i-1)*step,i,1,10

  ! using this, along with the initmymod setup.  Works, but would prefer to use a parameter array
  real, dimension(n), protected :: vals

  contains
    subroutine initmymod()
      integer :: i
      do i = 1,n
         vals(i) = startval+(i-1)*step
      end do
    end subroutine

    subroutine printinit()
      print *, vals
    end subroutine

end module


program main
  use mymod
  implicit none
  call initmymod
  call printinit
end program main

Upvotes: 1

Views: 958

Answers (2)

francescalus
francescalus

Reputation: 32451

Ian Bush's answer gives an explicit example of how to set the value of the array constant. I'll give a little more detail on that.

The value of a named constant in

<type>, parameter[, <attr>] :: named_constant = initexpr

is given by the value of initexpr, converted if necessary to the type of named_constant.

initexpr must be a constant expression and to be used for an array's value must be an array of the same shape or a scalar value (or of the same rank if the constant is an implied shape array).

What is it that we can use to make initexpr an array constant expression? There are several ways, but naturally in this case we want to use an array constructor. The rules in Fortran 2018 10.1.12 tell us what we have to keep in mind to have a array constructor a constant expression.

From Ian Bush's answer, in [ ( startval+(i-1)*step,i=1,n ) ] we have such a thing:

  • 1 and n (the loop control) are constants
  • startval and step are constants, and i is a constant, in the value calculation, so that whole expression is a constant expression

If any of those things aren't constants, then the array constructor isn't a constant expression and would be unsuitable to be used. Otherwise, you've quite a bit of freedom. The rules referenced give other ideas beyond this array constructor.

Finally, you can also make the array named constant implied shape:

real, parameter, dimension(*) :: vals_p = [ ( startval+(i-1)*step,i=1,n ) ]

rather than repeating the size of the array.

Upvotes: 2

Ian Bush
Ian Bush

Reputation: 7432

Something like this? It uses an implied do loop and an array constructor

ian@eris:~/work/stack$ cat construct.f90
module mymod
  implicit none
  private
  public :: printinit

  integer, parameter :: n=11
  real, parameter :: startval=10.,stopval=20.,step=(stopval-startval)/(n-1)

  ! would rather use something like this parameter statement than a protected array, is it possible?
!!$  real, parameter :: vals_p(n) = startval+(i-1)*step,i,1,10
  Integer :: i
  real, parameter, Dimension( 1:n ) :: vals_p = [ ( startval+(i-1)*step,i=1,n ) ]

  ! using this, along with the initmymod setup.  Works, but would prefer to use a parameter array

  contains

    subroutine printinit()
      print *, vals_p
    end subroutine

end module


program main
  use mymod
  implicit none
  call printinit
end program main

ian@eris:~/work/stack$ gfortran-8 --version
GNU Fortran (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-8 -std=f2003 -Wall -Wextra -fcheck=all construct.f90
ian@eris:~/work/stack$ ./a.out
   10.0000000       11.0000000       12.0000000       13.0000000       14.0000000       15.0000000       16.0000000       17.0000000       18.0000000       19.0000000       20.0000000  

Upvotes: 4

Related Questions