Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29274 Discussions

Passing a complex to real array in a subroutine call in Intel Visual Fortran 11.1

david_sallngc_com
2,450 Views
Hi!

I get an error (6633) trying to pass a complex array into a subroutine that has a real value as the dummy argument. A short snippet of code is as follows,

implicit none
integer :: i, N
complex*16, allocatable :: c(:)

N = 5
allocate (c(N))

! will load c such that c(1) = (1,2), c(2) = (3,4), ...
do i = 1,N
c(i) = dcmplx(dble(2*i-1), dble(2*i))
end do

call donothing(N, c)

deallocate (c)

end
subroutine donothing(N, r)
implicit none
integer :: N
real*8 :: r(2*N)

! looking to see r such that r(1) = 1, r(2) = 2, r(3) = 3, ...
return
end

I get the error, 6633, "The type of actual argument differs from the type of the dummy argument. " I have used this many times in the past but Intel Fortran 11.1 will not compile the code.

This technique is also used throughout the entire FFTPACK Fortran code from NCAR. It also will not compile correctly.

Is there a project setup option that will allow me to compile and run this code?

Thank you very much for your help.

Sincerely,

David
0 Kudos
6 Replies
Steven_L_Intel1
Employee
2,450 Views
In the Fortran > Diagnostics property page, turn off "Check Routine Interfaces". Your code is not legal Fortran, despite it being a common practice.
0 Kudos
david_sallngc_com
2,450 Views
Hi Steve!

This works great. Thanks!

BTW, is there another way of doing this in a standard Fortran fashion? I did not show it in my example, but I will be making changes to the array, R, in the subroutine and passing it back to the main program. I tried using the transfer intrinsic,

call donothing(N, transfer(c, 1.d0, 2*N))

and this worked except that any changes I made in the subroutine did not carry over back into the calling routine.

Thanks again Steve.

David
0 Kudos
TimP
Honored Contributor III
2,450 Views
The transfer expression is saved in a temporary, so it has a one-way effect. The array inside the transfer is protected against modification.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,450 Views
...because TRANSFER does the copy, not the "C-style cast".

I'm not sure if it 100% qualifies as "Standard Fortran", but you can [ab]use C interoperability to assign a Fortran complex POINTER array to a real array:

[fortran]use ISO_C_BINDING

complex(8), allocatable :: c(:)
real(8), pointer:: p(:)

allocate(c(N))
call C_F_POINTER(C_LOC(c), p, [2*N])
call donothing(N, p)[/fortran]
Still, I'm not positive that it's illegal to map a real to a complex array in your original sample, but I suppose Steve did check.
0 Kudos
david_sallngc_com
2,450 Views
Hi Jugoslav!

I am by no means a pointer expert but wouldn't your technique require an additional 2*N*8 bytes of storage? In fact, I believe you can use the TRANSFER intrinsic to create p from c without using c_f_pointer.

My original code (i.e., the non-standard Fortran) uses the same memory but I just access and useit differently, i.e., real versus complex array.

Thanks for your help!

Sincerely,

David
0 Kudos
Jugoslav_Dujic
Valued Contributor II
2,450 Views
No, my technique does not require any additional storage, and it does not involve any copying of the data. The C_F_POINTER line, in effect, does a run-time equivalence, i.e.

p => c

Of course, the above line is not allowed in standard Fortran, and that's why you have to "cheat".

The TRANSFER does the copying of bytes from the source argument to the result. You might use it for an input argument to the routine expecting a real, but since its result is a temporary, you may not associate it with an output argument.
0 Kudos
Reply