In How to pass subroutine names as arguments in Fortran? we learned how to pass subroutine names as arguments in Fortran. How can we do this inside a class structure?
The ensuing code produces the following compilation error using GNU Fortran (GCC) 5.1.0:
gfortran -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5 class_pass.f08
myClass.f08:44:30:
class ( test ), target :: me
1
Error: Derived type ‘test’ at (1) is being used before it is defined
myClass.f08:9:21:
procedure, public :: action => action_sub
1
Error: Non-polymorphic passed-object dummy argument of ‘action_sub’ at (1)
myClass.f08:40:36:
class ( test ), target :: me
1
Error: CLASS variable ‘me’ at (1) must be dummy, allocatable or pointer
(null):0: confused by earlier errors, bailing out
The main routine follows. It includes a routine check used as a diagnostic.
include 'myClass.f08'
program class_pass
use myClass
implicit none
type ( test ) :: myTest
call myTest % check ()
call myTest % action ( square_sub )
end program class_pass
The module:
module myClass
implicit none
type :: test
real :: x, y
contains
private
procedure, public :: action => action_sub
procedure, public :: square => square_sub
procedure, public :: double => double_sub
procedure, public :: check => check_sub
end type test
private :: action_sub
private :: square_sub
private :: double_sub
private :: check_sub
contains
subroutine square_sub ( me )
class ( test ), target :: me
me % y = me % x ** 2
end subroutine square_sub
subroutine double_sub ( me )
class ( test ), target :: me
me % y = me % x * 2
end subroutine double_sub
subroutine check_sub ( me )
class ( test ), target :: me
me % x = 5.0
call double_sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine check_sub
subroutine action_sub ( sub )
class ( test ), target :: me
interface mySub
subroutine sub ( me )
class ( test ), target :: me
end subroutine sub
end interface mySub
call sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine action_sub
end module myClass
Many thanks to #Vladimir F for the original solution and tips.
Your errors are due to missing parameters in your procedure action_sub and a few other minor things. This procedure is bound to your derived type via
procedure, public :: action => action_sub
and by default the polymorphic class variable is passed as the first argument to action_sub. You have correctly accounted for this in your other type bound procedures, but are missing it in this procedure. You also need to import the derived type in the interface block within action_sub in order to use the type there. This modified version of just that procedure allows your module to compile properly:
subroutine action_sub ( me, sub )
class ( test ), target :: me
interface mySub
subroutine sub ( me )
import test
class ( test ), target :: me
end subroutine sub
end interface mySub
call sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine action_sub
next, in your main program where you do:
call myTest % action ( square_sub )
in order to reference square_sub here you need to make the procedure public in your module. Once you remove the private attribute from the module procedure your code compiles and runs:
x = 5.00000000 , y = 10.0000000
x = 5.00000000 , y = 25.0000000
Related
I have a very large vector in which I want to add the total number of elements as a condition that repeat numbers do not characterize a new element, for example:
V=[0,5,1,8,9,1,1,]
My desired answer would be:5
But I can't think of a way to do that because with the count function I would have to know all the elements of my vector.
count function not works in this case
FWIW, here's a solution using a tree. No attempt to balance it.
module treemodule
implicit none
private
public numDistinct
type Node
integer value
type(Node), pointer :: left => null(), right => null()
end type node
type, public :: Tree
private
type(Node), pointer :: root => null()
integer :: size = 0
contains
procedure insert
procedure clear
procedure print
procedure getsize
procedure, private :: insertNode
procedure, private :: deleteNode
procedure, private :: printNode
end type Tree
contains
integer function numDistinct( A )
integer, intent(in) :: A(:)
integer i
type(Tree) T
numDistinct = 3
do i = 1, size( A )
call T%insert( A(i) )
end do
numDistinct = T%getsize()
! Comment out the following if you don't need it ...
write( *, "(A)", advance="no" ) "Distinct elements: "; call T%print; write( *, * )
call T%clear
end function numDistinct
integer function getsize( this )
class(Tree) this
getsize = this%size
end function getsize
subroutine insert( this, value )
class(Tree) this
integer, intent(in) :: value
call this%insertNode( this%root, value )
end subroutine insert
subroutine print( this )
class(Tree) this
call this%printNode( this%root )
end subroutine print
subroutine clear( this )
class(Tree) this
call this%deleteNode( this%root )
end subroutine clear
recursive subroutine insertNode( this, ptr, value )
class(Tree) this
type(Node), pointer, intent(inout) :: ptr
integer value
if ( associated( ptr ) ) then
if ( value < ptr%value ) then
call this%insertNode( ptr%left, value )
else if ( value > ptr%value ) then
call this%insertNode( ptr%right, value )
end if
else
allocate( ptr, source=Node(value) )
this%size = this%size + 1
end if
end subroutine insertNode
recursive subroutine deleteNode( this, ptr )
class(Tree) this
type(Node), pointer, intent(inout) :: ptr
if ( associated( ptr ) ) then
call this%deleteNode( ptr%left )
call this%deleteNode( ptr%right )
deallocate( ptr )
this%size = this%size - 1
end if
end subroutine deleteNode
recursive subroutine printNode( this, ptr )
class(Tree) this
type(Node), pointer, intent(in) :: ptr
if ( associated( ptr ) ) then
call this%printNode( ptr%left )
write ( *, "( i0, 1x )", advance="no" ) ptr%value
call this%printNode( ptr%right )
end if
end subroutine printNode
end module treemodule
!=======================================================================
program main
use treemodule
implicit none
integer, allocatable :: A(:)
integer C
A = [ 0, 5, 1, 8, 9, 1, 1 ]
C = numDistinct( A )
write( *, "( 'Number of distinct elements = ', i0 )" ) C
end program main
Distinct elements: 0 1 5 8 9
Number of distinct elements = 5
If you don't care about memory and performances (otherwise there are more efficient codes in the link given by Francescalus):
integer function count_unique(x) result(n)
implicit none
integer, intent(in) :: x(:)
integer, allocatable :: y(:)
y = x(:)
n = 0
do while (size(y) > 0)
n = n+1
y = pack(y,mask=(y(:) /= y(1)) ! drops all elements that are
! equals to the 1st one (included)
end do
end function count_unique
What is the best method when you need interchange the values in two polymorphic elements? (Using standard fortran 2008).
I'm sending an example (please try don't modify the type variables).
The problems that I have using intel compiler v.19 and gfortran 8.1 in windows are different.
Here a complete example. Look at the subroutine where I have defined the swap procedure. Currently is activate the version that works in GFortran but I have error with intel compiler. If you comment this part and uncomment the lines for ifort, then works for intel and not for gfortran....
Program Check
implicit none
!> Type definitions
Type :: Refl_Type
integer,dimension(:), allocatable :: H
integer :: Mult =0
End Type Refl_Type
Type :: RefList_Type
integer :: Nref
class(refl_Type), dimension(:), allocatable :: Reflections
end Type RefList_Type
Type(RefList_Type) :: List
Type(Refl_Type), dimension(3) :: Refl_Ini
!> Variables
integer :: i
!> Init
Refl_Ini(1)%H=[1, 0, 0]; Refl_Ini(1)%Mult=1
Refl_Ini(2)%H=[0, 2, 0]; Refl_Ini(2)%Mult=2
Refl_Ini(3)%H=[0, 0, 3]; Refl_Ini(3)%Mult=3
List%Nref=3
List%Reflections=Refl_Ini
!> Print Step:1
do i=1, List%Nref
print '(i3,2x,3i4,2x,i3)', i,List%Reflections(i)%H, List%Reflections(i)%Mult
end do
print*,' '
print*,' '
!> Swap
call Swap_Elements_List(List, 1, 3)
!> Print Step:2
do i=1, List%Nref
print '(i3,2x,3i4,2x,i3)', i,List%Reflections(i)%H, List%Reflections(i)%Mult
end do
Contains
Subroutine Swap_Elements_List(List, i, j)
!---- Argument ----!
type (RefList_Type), intent(in out) :: List
integer, intent(in) :: i,j
!---- Local Variables ----!
class(Refl_Type), allocatable :: tmp
!> IFort
!tmp=List%reflections(i)
!List%reflections(i)=List%reflections(j)
!List%reflections(j)=tmp
!> Gfortran
associate(t1 => list%reflections(i), t2 => list%reflections(j), tt => tmp)
tt=t1
t1=t2
t2=tt
end associate
End Subroutine Swap_Elements_List
End Program Check
Any suggestion?
Compiling the original code with gfortran-8.2 gives
test.f90:34:6:
List%reflections(i)=List%reflections(j) !!<---
1
Error: Nonallocatable variable must not be polymorphic in
intrinsic assignment at (1) - check that there is a
matching specific subroutine for '=' operator
I think this is because List % reflections(i) is not separately allocatable (even though List % reflections itself is allocatable as an array of uniform type). This point seems to be discussed in detail, e.g., in this Q/A page, which suggests two alternative approaches: (A) convince the compiler that all elements will be of the same type; or (B) use an (array) container.
If we use the "container" approach, I think we can use move_alloc() to swap two polymorphic objects (without knowing the dynamic type). For example, a bit modified version of the original code may be
program main
implicit none
type :: Refl_t
integer, allocatable :: H(:)
endtype
type, extends(Refl_t) :: ExtRefl_t
real :: foo
endtype
type :: RefList_t
class(Refl_t), allocatable :: refl
endtype
type(RefList_t) :: list( 3 )
call init()
print *, "Before:"
call output()
call swap( 1, 2 )
print *, "After:"
call output()
contains
subroutine swap( i, j )
integer, intent(in) :: i, j
class(Refl_t), allocatable :: tmp
call move_alloc( from= list( i )% refl, to= tmp )
call move_alloc( from= list( j )% refl, to= list( i )% refl )
call move_alloc( from= tmp, to= list( j )% refl )
end
subroutine init()
integer i
do i = 1, 3
allocate( ExtRefl_t :: list( i ) % refl )
select type( x => list( i ) % refl )
type is ( ExtRefl_t )
x % H = [ i, i * 10 ]
x % foo = i * 100
endselect
enddo
end
subroutine output()
integer i
do i = 1, 3
select type( x => list( i ) % refl )
type is ( ExtRefl_t )
print *, "i = ", i, " : H = ", x % H, " foo = ", x % foo
endselect
enddo
end
end program
Result (gfortran-8.2):
Before:
i = 1 : H = 1 10 foo = 100.000000
i = 2 : H = 2 20 foo = 200.000000
i = 3 : H = 3 30 foo = 300.000000
After:
i = 1 : H = 2 20 foo = 200.000000
i = 2 : H = 1 10 foo = 100.000000
i = 3 : H = 3 30 foo = 300.000000
I think we could also use polymorphic assignment for the above swap() routine, for example:
subroutine swap( i, j )
integer, intent(in) :: i, j
class(Refl_t), allocatable :: tmp
tmp = list( i ) % refl
list( i ) % refl = list( j ) % refl
list( j ) % refl = tmp
end
This compiles with gfortran-8.2, but gives a strange result... (a possible compiler bug?). I guess newer compilers like GCC-9 or Intel Fortran may give an expected result.
On the other hand, if we use a polymorphic array, we may need to use select type explicitly for swapping the two elements. (But I hope there is a different approach...) The code may then look like:
program main
implicit none
type :: Refl_t
integer, allocatable :: H(:)
endtype
type, extends(Refl_t) :: ExtRefl_t
real :: foo
endtype
class(Refl_t), allocatable :: refls( : )
allocate( ExtRefl_t :: refls( 3 ) )
call init()
print *, "Before:"
call output()
call swap( 1, 2 )
print *, "After:"
call output()
contains
subroutine swap( i, j )
integer, intent(in) :: i, j
selecttype ( refls )
type is ( ExtRefl_t )
block
type(ExtRefl_t) :: tmp
tmp = refls( i ) !<-- assignment of concrete type
refls( i ) = refls( j )
refls( j ) = tmp
endblock
class default
stop
endselect
end
subroutine init()
integer i
select type( refls )
type is ( ExtRefl_t )
do i = 1, 3
refls( i ) % H = [ i, i * 10 ]
refls( i ) % foo = i * 100
enddo
endselect
end
subroutine output()
integer i
select type( refls )
type is ( ExtRefl_t )
do i = 1, 3
print *, "i = ", i, " : H = ", refls( i ) % H, &
" foo = ", refls( i ) % foo
enddo
endselect
end
end program
(The result is the same as above.)
The answer by roygvib summarizes the problem well. If this assignment is to be performed in user's code where the types are known or are known to be from a small set of possible types, one can just protect the assignment by the select type typeguard.
The real problem happens in a generic code that is written without the knowledge of the user's derived types. Therefore it may have no access to possible user-defined assignments. I suggest a possible solution using a callback procedure. Basically, the user defines an assignment or swap procedure which is then called by the library code.
subroutine sub_that_needs_assignments(array, assign)
class(*) :: array
interface
subroutne assign(out, in)
end subroutine
end interface
call assign(array(i), array(i+1))
!or you can even assign a new elemnt from somewhere else
! possibly protect by same_type_as()
end subroutine
in the user's code
subroutine assign_my_type(out, in)
class(*), ... :: out
class(*), ... :: in
select type (out)
type is (my_type)
select type (in) ! not always necessary
type is (in)
out = in
end select
end select
!add appropriate error checking
end subroutine
I am not experienced programer in fortran so I need a help about my simple code.
My code is:
module derived_type
implicit none
type :: iter_type
integer :: calc_tmp
integer :: n_iter
contains
procedure :: calc_iter => calc_iter_process
procedure :: take_calc_tmp => take_data_calc_tmp
procedure :: take_n_iter => take_data_n_iter
end type iter_type
private :: calc_iter_process
private :: take_data_calc_tmp
private :: take_data_n_iter
contains
function calc_iter_process( this, indx_00 ) result( err_tmp )
class( iter_type ) :: this
integer, intent( in ) :: indx_00
logical :: err_tmp
err_tmp = .false.
this%n_iter = 0
this%calc_tmp = 1
do while( this%calc_tmp < indx_00 )
this%n_iter = this%n_iter + 1
if ( this%n_iter > 50 ) then
write(*,*) "error - maximal number of iterations !!!"
err_tmp = .true.
exit
end if
this%calc_tmp = this%calc_tmp + 1
end do
end function calc_iter_process
function take_data_calc_tmp( this ) result( data_tmp )
class( iter_type ) :: this
integer :: data_tmp
data_tmp = this%calc_tmp
end function take_data_calc_tmp
function take_data_n_iter( this ) result( data_tmp )
class( iter_type ) :: this
integer :: data_tmp
data_tmp = this%n_iter
end function take_data_n_iter
end module derived_type
program iteration_values
use, non_intrinsic :: derived_type
implicit none
integer, parameter :: number_00 = 32
logical :: global_err
type( iter_type ) :: iter_object
global_err = iter_object%calc_iter( number_00 )
if ( global_err ) stop "error - global !!!"
end program iteration_values
I need to find way for code modification which can give me a way to keep or save value of 'calc_tmp' in every single iterations.
When I thinking about that I can not imagine how to allocate or deallocate some array which must be dimension same or higher the 'n_iter'.
Is there way for doing that?
I would recommend the use of the allocatable attribute and move_alloc. Here is an example program. move_alloc is Fortran 2003. In this example, I'm increasing the size of the array every time its size is exceeded.
program temp
implicit none
integer, dimension(:), allocatable :: tempval, calc_tmp_history
integer :: i, j, calc_tmp, totalSize
totalSize = 0
allocate(calc_tmp_history(2))
do i = 1,4
calc_tmp = 2*i
if (i > size(calc_tmp_history)) then
call move_alloc(calc_tmp_history,tempval)
allocate(calc_tmp_history(2*i))
do j = 1,i
calc_tmp_history(j) = tempval(j)
end do
end if
calc_tmp_history(i) = calc_tmp
totalSize = totalSize + 1
end do
do i = 1,totalSize
print *, calc_tmp_history(i)
end do
end program
Output from this is:
2
4
6
8
I am new to Fortran so I would like to have some insight regarding the allocation of dynamic memory
I read about dynamic memory allocation and various sources have a different take to this subject. For example, one book states that every single block of allocated dynamic memory must be deallocated at the end of the program to avoid memory leaks. However, other sources (books and various web pages) claim that is invalid as compilers (gfortran and alike) deallocate
all dynamic objects, arrays, etc automatically at the end of the program.
So in my sample code, I do not know if there is a need to deallocate dynamic array NN_VOD from CALCULATE_DATA_DM procedure.
What do I need to do with this sample code if I want to avoid memory leak and are there any memory leak in this code? (My IDE is Code::Blocks 17.12 with MinGW compiler 6.3.0)
MODULE DERRIVED_TYPE_TMP
INTEGER, PUBLIC :: I, J, K, ALLOC_ERR
TYPE, PUBLIC :: DM_ELEMENT
CHARACTER( 50 ), PRIVATE :: ELE_NAME
INTEGER, PRIVATE :: ELE_NUMBER
CONTAINS
PROCEDURE, PUBLIC :: CALCULATE_ELEMENT => CALCULATE_DATA_ELEMENT
END TYPE DM_ELEMENT
PRIVATE :: CALCULATE_DATA_ELEMENT
TYPE, EXTENDS(DM_ELEMENT), PUBLIC :: VOD_DM
INTEGER, ALLOCATABLE, PRIVATE :: NN_VOD( : )
CONTAINS
PROCEDURE, PUBLIC :: CALCULATE_ELEMENT => CALCULATE_DATA_DM
PROCEDURE, PUBLIC :: TAKE_DM => TAKE_DATA_DM
END TYPE VOD_DM
PRIVATE :: CALCULATE_DATA_DM
PRIVATE :: TAKE_DATA_DM
CONTAINS
SUBROUTINE CALCULATE_DATA_ELEMENT ( THIS, NUMBER_TMP )
CLASS( DM_ELEMENT ) :: THIS
INTEGER, INTENT( IN ) :: NUMBER_TMP
END SUBROUTINE CALCULATE_DATA_ELEMENT
SUBROUTINE CALCULATE_DATA_DM( THIS, NUMBER_TMP )
CLASS( VOD_DM ) :: THIS
INTEGER, INTENT( IN ) :: NUMBER_TMP
IF ( .NOT. ALLOCATED( THIS%NN_VOD ) ) ALLOCATE( THIS%NN_VOD( NUMBER_TMP ), STAT = ALLOC_ERR )
IF ( ALLOC_ERR .NE. 0 ) STOP ( "PROBLEM SA ALOKACIJOM MEMORIJE - THIS%T !!!" )
DO J = 1, NUMBER_TMP
THIS%NN_VOD( J ) = J + NUMBER_TMP
END DO
END SUBROUTINE CALCULATE_DATA_DM
FUNCTION TAKE_DATA_DM( THIS, INDX ) RESULT( RESULT_TMP )
CLASS( VOD_DM ) :: THIS
INTEGER, INTENT( IN ) :: INDX
INTEGER :: RESULT_TMP
RESULT_TMP = THIS%NN_VOD( INDX )
END FUNCTION TAKE_DATA_DM
END MODULE DERRIVED_TYPE_TMP
PROGRAM DO_LOOP_ALLOCATION
USE, NON_INTRINSIC :: DERRIVED_TYPE_TMP
IMPLICIT NONE
INTEGER, PARAMETER :: N_NN_DM = 3
INTEGER, PARAMETER :: AN_NN_DM( N_NN_DM ) = [ 2, 3, 4 ]
TYPE :: NN_VOD
TYPE( VOD_DM ), ALLOCATABLE :: ID( : )
END TYPE NN_VOD
CLASS( DM_ELEMENT ), POINTER :: P_DM_ELEMENT
TYPE ( NN_VOD ), ALLOCATABLE, TARGET :: PAR_NN_VOD( : )
IF ( .NOT. ALLOCATED( PAR_NN_VOD ) ) ALLOCATE( PAR_NN_VOD( N_NN_DM ), STAT = ALLOC_ERR )
IF ( ALLOC_ERR .NE. 0 ) STOP ( "ALLOCATION ERROR - PAR_NN_VOD !!!" )
DO K = 1, N_NN_DM
IF ( .NOT. ALLOCATED( PAR_NN_VOD( K )%ID ) ) ALLOCATE( PAR_NN_VOD( K )%ID( AN_NN_DM( K ) ), STAT = ALLOC_ERR )
IF ( ALLOC_ERR .NE. 0 ) STOP ( "ALLOCATION ERROR - PAR_NN_VOD%ID !!!")
END DO
DO K = 1, N_NN_DM
DO I = 1, AN_NN_DM( K )
P_DM_ELEMENT => PAR_NN_VOD( K )%ID( I )
CALL P_DM_ELEMENT%CALCULATE_ELEMENT( K + I )
END DO
END DO
END PROGRAM DO_LOOP_ALLOCATION
From Fortran95 onwards the language is designed so that with a standard conforming compiler it is impossible to have a memory leak when using allocatable arrays, as once an allocatable object goes out of scope it becomes deallocated. This is one of the big advantages of allocatable arrays, and one of the reasons why they should always be used in preference to pointers where possible. Now when a variable goes out of scope may well be long after a variable stops being used, and so you may wish to manually deallocate earlier to save memory, but there is no need to deallocate purely to avoid a memory leak. Thus in your code use allocatable arrays and there will be no memory leak.
In Fortran 90 this was not true, memory leaks with allocatables were possible. But this standard has long been superseded by Fortran 95 and it, and thus Fortran 90 and all earlier standards should not be being used today.
Consider the following "real world" legacy Fortran 77 code, which may well be illegal according to the standard, but works in real life with a wide range of compilers, and produces no compiler or linker warnings if each subroutine is compiled separately.
subroutine a
complex z(10)
call b(z)
call r1(z)
call r2(z)
end
subroutine b(z)
complex z(10)
c ... use complex arithmetic on z
end
subroutine r1(x)
real x(2,10)
c ... do something with real and imaginary parts
c ... real parts are x(1,*)
c ... imaginary parts are x(2,*)
end
subroutine r2(x)
real x(20)
c ... do something with real and imaginary parts
end
I want to re-package code in this style using Fortran 90/95 modules. The naïve approach of
module m
public a
private b, r1, r2
contains
subroutine a
complex z(10)
call b(z)
call r1(z)
call r2(z)
end subroutine a
subroutine b(z)
complex z(10)
c ... use complex arithmetic on z
end subroutine b
subroutine r1(x)
real x(2,10)
c ... do something with real and imaginary parts
c ... real parts are x(1,*)
c ... imaginary parts are x(2,*)
end subroutine r1
subroutine r2(x)
real x(20)
c ... do something with real and imaginary parts
end subroutine r2
end module m
doesn't compile, because (of course) the compiler can now see that subroutines r1 and r2 are called with the wrong argument type.
I need some ideas on how to fix this, with the minimum amount of rewriting of the existing code, and without making duplicate copies of the data in memory - the real-life size of the data is too big for that.
c_f_pointer() may be useful to get a real(2,*) pointer to a complex(*) array, but I am not sure whether passing the complex parameter (zconst(:)) to ctor() is really okay... (here I have used gfortran 4.4 & 4.8 and ifort 14.0, and to make the output more compact the array dimension is changed from 10 to 3.)
module m
implicit none
contains
subroutine r1 ( x )
real x( 2, 3 )
print *
print *, "In r1:"
print *, "Real part = ",x( 1, : )
print *, "Imag part = ",x( 2, : )
endsubroutine
subroutine r2 ( x )
real x( 6 )
print *
print *, "In r2:"
print *, "all elements = ", x( : )
endsubroutine
subroutine b ( z )
complex :: z( 3 )
real, pointer :: rp(:,:)
rp => ctor( z, 3 ) !! to compare z and rp
print *
print *, "In b:"
print *, "1st elem = ", z( 1 ), rp( :, 1 )
print *, "3rd elem = ", z( 3 ), rp( :, 3 )
endsubroutine
function ctor( z, n ) result( ret ) !! get real(2,*) pointer to complex(*)
use iso_c_binding
implicit none
integer :: n
complex, target :: z( n )
real, pointer :: ret(:,:)
call c_f_pointer( c_loc(z(1)), ret, shape=[2,n] )
endfunction
endmodule
program main
use m
implicit none
complex z(3)
complex, parameter :: zconst(3) = [(7.0,-7.0),(8.0,-8.0),(9.0,-9.0)]
z(1) = ( 1.0, -1.0 )
z(2) = ( 2.0, -2.0 )
z(3) = ( 3.0, -3.0 )
call r1 ( ctor( z, 3 ) )
call r1 ( ctor( zconst, 3 ) )
call r2 ( ctor( z, 3 ) )
call r2 ( ctor( zconst, 3 ) )
call b ( z )
call b ( zconst )
endprogram
Note the following suggestion has some retrogressive aspects.
In the example code in the question, the original source of the data is a local variable. Such a local variable can appear in a storage association context by using an equivalence statement, and in such a context it is possible to treat a COMPLEX object as a pair of REAL objects.
module m
public a
private b, r1, r2
contains
subroutine a
complex z(10)
real r(size(z)*2)
equivalence (z,r)
call b(z) ! pass complex array
call r1(r) ! pass real array
call r2(r) ! pass real array
end subroutine a
subroutine b(z)
complex z(10)
! ... use complex arithmetic on z
end subroutine b
subroutine r1(x)
real x(2,10)
! ... do something with real and imaginary parts
! ... real parts are x(1,*)
! ... imaginary parts are x(2,*)
end subroutine r1
subroutine r2(x)
real x(20)
! ... do something with real and imaginary parts
end subroutine r2
end module m
(This is perhaps more a comment than an answer, but you can't include formatted code in a comment).
#roygvib answered the question in standard fortran 2003.
The same idea can be coded more concisely using the non-standard "Cray Fortran pointer" syntax which is implemented in many compilers - for example the -fcray-pointer option in gfortran. The non-standard intrinsic function loc replaces ctor.
subroutine b ( z )
complex :: z( 3 )
real :: r( 2, 3 )
pointer(zp, r)
zp = loc(z)
print *
print *, "In b:"
print *, "1st elem = ", z( 1 ), r( :, 1)
print *, "3rd elem = ", z( 3 ), r( :, 3)
endsubroutine