user6599829
user6599829

Reputation:

Initialization of a Fortran parameter with intent(in) argument

Consider the following programm :

Subroutine foo(p,v)
  implicit none
  integer,                         intent(in)  :: p
  double precision,  dimension(p), intent(in)  :: v 

  !local variables
  integer,parameter :: n=floor(par(p))
  double precision  :: z(2*n)

[...]
End Subroutine

I get the following error:

Error: Array ‘v’ at (1) is a variable, which does not reduce to a constant expression

which is quite explicit but I would like to know if there is a way to manage that kind of situation: assign an intent(in) argument of the subroutine to a parameter variable?

Upvotes: 2

Views: 986

Answers (2)

user5713492
user5713492

Reputation: 974

You can use zero-length variables to hold intermediate results that can be extracted from them via specification inquiries. Time for an example:

module mod_par
   implicit none
   contains
      pure function par(x)
         double precision par
         integer, intent(in) :: x
         par = 1+sqrt(real(1,kind(par))+x)
      end function par
end module mod_par

module mod_foo
!   use mod_par
   implicit none
   double precision par
   contains
      subroutine foo(p,v)
         implicit none
         integer p
         double precision v
         character(0) sv_i(floor(par(p)))
         character(floor(par(p))) sv_j(0)
         logical sv_k(floor(par(p)),0)
         type t
         ! Intentionally empty
         end type t
         type(t) sv_L(floor(par(p)))
         type u(len)
            integer, len :: len
         ! intentionally empty
         end type u
         type(u(floor(par(p)))) sv_m
         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
!         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
         write(*,*) shape(z)
      end subroutine foo
end module mod_foo

program bar
   use mod_par
   use mod_foo
   implicit none
   call foo(10,1.0d0)
end program bar

This fails on both ifort and gfortran because a specification function, here par, must be PURE and its interface must be explicit. Here par, though PURE has an implicit interface, so it's rejected. In fact both compilers seem to get confused:

specvar.f90:21:25:

          character(floor(par(p))) sv_j(0)
                         1
Error: Function 'par' at (1) has no IMPLICIT type

For gfortran, and ifort says

specvar.f90(31): error #6404: This name does not have a type, and must have an e
xplicit type.   [PAR]
         type(u(floor(par(p)))) sv_m
----------------------^

So we fix this programming error...

module mod_par
   implicit none
   contains
      pure function par(x)
         double precision par
         integer, intent(in) :: x
         par = 1+sqrt(real(1,kind(par))+x)
      end function par
end module mod_par

module mod_foo
   use mod_par
   implicit none
!   double precision par
   contains
      subroutine foo(p,v)
         implicit none
         integer p
         double precision v
         character(0) sv_i(floor(par(p)))
         character(floor(par(p))) sv_j(0)
         logical sv_k(floor(par(p)),0)
         type t
         ! Intentionally empty
         end type t
         type(t) sv_L(floor(par(p)))
         type u(len)
            integer, len :: len
         ! intentionally empty
         end type u
         type(u(floor(par(p)))) sv_m
         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
!         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
         write(*,*) shape(z)
      end subroutine foo
end module mod_foo

program bar
   use mod_par
   use mod_foo
   implicit none
   call foo(10,1.0d0)
end program bar

But now gfortran says

specvar.f90:32:73:

          double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%l
en,0)
                                                                         1
Error: Variable 'sv_m' cannot appear in the expression at (1)

And ifort:

specvar.f90(31): error #6279: A specification expression object must be a dummy
argument, a COMMON block object, or an object accessible through host or use ass
ociation.   [SV_M]
         type(u(floor(par(p)))) sv_m
--------------------------------^

So I don't have a sufficiently recent version of either compiler to support type parameter inquiries. Bummer. So we get rid of that last bit...

module mod_par
   implicit none
   contains
      pure function par(x)
         double precision par
         integer, intent(in) :: x
         par = 1+sqrt(real(1,kind(par))+x)
      end function par
end module mod_par

module mod_foo
   use mod_par
   implicit none
!   double precision par
   contains
      subroutine foo(p,v)
         implicit none
         integer p
         double precision v
         character(0) sv_i(floor(par(p)))
         character(floor(par(p))) sv_j(0)
         logical sv_k(floor(par(p)),0)
         type t
         ! Intentionally empty
         end type t
         type(t) sv_L(floor(par(p)))
         type u(len)
            integer, len :: len
         ! intentionally empty
         end type u
         type(u(floor(par(p)))) sv_m
!         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
         double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
         write(*,*) shape(z)
      end subroutine foo
end module mod_foo

program bar
   use mod_par
   use mod_foo
   implicit none
   call foo(10,1.0d0)
end program bar

And now both compilers produce good code. So you can see that there are many ways to save a temporary integer variable in specifications of zero-length automatic variables that can be used in further specification expressions. Note that if you get too fancy with this kind of syntax you will crash the compiler a lot.

Upvotes: 0

No, that is impossible. A parameter is a compile-time constant. Its value cannot come from any argument or variable.

It is also not clear at all why would you want to do that (see https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem ). You do not need a parameter to declare an array

double precision :: z(2*floor(par(p)))

because in automatic arrays the bounds can be procedure arguments.

Upvotes: 5

Related Questions